diff --git a/powertools-batch/pom.xml b/powertools-batch/pom.xml index b389df6fe..850be6922 100644 --- a/powertools-batch/pom.xml +++ b/powertools-batch/pom.xml @@ -50,6 +50,16 @@ powertools-serialization ${project.version} + + software.amazon.lambda + powertools-common + ${project.version} + + + software.amazon.awssdk + sdk-core + provided + @@ -57,12 +67,6 @@ junit-jupiter-api test - - org.slf4j - slf4j-simple - 2.0.17 - test - org.assertj assertj-core @@ -83,6 +87,11 @@ slf4j-simple test + + software.amazon.awssdk + s3 + test + - \ No newline at end of file + diff --git a/powertools-batch/src/main/java/software/amazon/lambda/powertools/batch/internal/BatchUserAgentInterceptor.java b/powertools-batch/src/main/java/software/amazon/lambda/powertools/batch/internal/BatchUserAgentInterceptor.java new file mode 100644 index 000000000..f49dbe5c5 --- /dev/null +++ b/powertools-batch/src/main/java/software/amazon/lambda/powertools/batch/internal/BatchUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.batch.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-batch module is on the classpath. + */ +public final class BatchUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("batch"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-batch/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-batch/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..51764f87f --- /dev/null +++ b/powertools-batch/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.batch.internal.BatchUserAgentInterceptor diff --git a/powertools-batch/src/test/java/software/amazon/lambda/powertools/batch/internal/BatchUserAgentInterceptorTest.java b/powertools-batch/src/test/java/software/amazon/lambda/powertools/batch/internal/BatchUserAgentInterceptorTest.java new file mode 100644 index 000000000..2841a1724 --- /dev/null +++ b/powertools-batch/src/test/java/software/amazon/lambda/powertools/batch/internal/BatchUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.batch.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class BatchUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/BATCH/"); + } +} diff --git a/powertools-cloudformation/pom.xml b/powertools-cloudformation/pom.xml index ca4e7536f..d49fcc2bc 100644 --- a/powertools-cloudformation/pom.xml +++ b/powertools-cloudformation/pom.xml @@ -42,6 +42,10 @@ software.amazon.awssdk url-connection-client + + software.amazon.awssdk + sdk-core + com.amazonaws aws-lambda-java-core @@ -58,6 +62,11 @@ org.aspectj aspectjrt + + software.amazon.lambda + powertools-common + ${project.version} + @@ -102,6 +111,11 @@ test-jar test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/internal/CloudformationUserAgentInterceptor.java b/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/internal/CloudformationUserAgentInterceptor.java new file mode 100644 index 000000000..c225512d1 --- /dev/null +++ b/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/internal/CloudformationUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.cloudformation.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-cloudformation module is on the classpath. + */ +public final class CloudformationUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("cloudformation"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/reflect-config.json b/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/reflect-config.json index 218382888..092ef9b54 100644 --- a/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/reflect-config.json +++ b/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/reflect-config.json @@ -428,5 +428,9 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"software.amazon.lambda.powertools.cloudformation.internal.CloudformationUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/resource-config.json b/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/resource-config.json index f3b58337b..cbbfb270d 100644 --- a/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/resource-config.json +++ b/powertools-cloudformation/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-cloudformation/resource-config.json @@ -30,6 +30,8 @@ "pattern":"\\Qorg/eclipse/jetty/version/build.properties\\E" }, { "pattern":"\\Qorg/publicsuffix/list/effective_tld_names.dat\\E" + }, { + "pattern":"\\Qsoftware/amazon/awssdk/global/handlers/execution.interceptors\\E" }]}, "bundles":[{ "name":"jakarta.servlet.LocalStrings", diff --git a/powertools-cloudformation/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-cloudformation/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..172ca1d2c --- /dev/null +++ b/powertools-cloudformation/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.cloudformation.internal.CloudformationUserAgentInterceptor diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/internal/CloudformationUserAgentInterceptorTest.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/internal/CloudformationUserAgentInterceptorTest.java new file mode 100644 index 000000000..ee500d006 --- /dev/null +++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/internal/CloudformationUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.cloudformation.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class CloudformationUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/CLOUDFORMATION/"); + } +} diff --git a/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java b/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java index d2e592902..7deca89f1 100644 --- a/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java +++ b/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/UserAgentConfigurator.java @@ -18,26 +18,27 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Locale; import java.util.Properties; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * Can be used to create a string that can server as a User-Agent suffix in requests made with the AWS SDK clients */ -public class UserAgentConfigurator { - +public final class UserAgentConfigurator { public static final String NA = "NA"; public static final String VERSION_KEY = "powertools.version"; public static final String PT_FEATURE_VARIABLE = "${PT_FEATURE}"; public static final String PT_EXEC_ENV_VARIABLE = "${PT_EXEC_ENV}"; public static final String VERSION_PROPERTIES_FILENAME = "version.properties"; public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV"; + private static final String SDK_USER_AGENT_APP_ID = "sdk.ua.appId"; private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class); private static final String NO_OP = "no-op"; private static final String POWERTOOLS_VERSION = getProjectVersion(); - private static final String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + POWERTOOLS_VERSION + " PTEnv/" + private static final String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + POWERTOOLS_VERSION + " PTENV/" + PT_EXEC_ENV_VARIABLE; private UserAgentConfigurator() { @@ -53,7 +54,6 @@ static String getProjectVersion() { return getVersionFromProperties(VERSION_PROPERTIES_FILENAME, VERSION_KEY); } - /** * Retrieves the project version from a properties file. * The file should be in the resources folder. @@ -64,28 +64,46 @@ static String getProjectVersion() { * @return the version of the project as configured in the given properties file */ static String getVersionFromProperties(String propertyFileName, String versionKey) { - - InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(propertyFileName); - - if (is != null) { - try { + try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(propertyFileName)) { + if (is != null) { Properties properties = new Properties(); properties.load(is); String version = properties.getProperty(versionKey); if (version != null && !version.isEmpty()) { return version; } - } catch (IOException e) { - LOG.warn("Unable to read {} file. Using default version.", propertyFileName); - LOG.debug("Exception:", e); } + } catch (IOException e) { + LOG.warn("Unable to read {} file. Using default version.", propertyFileName); + LOG.debug("Exception:", e); } return NA; } + /** + * Configures the AWS SDK to use Powertools user agent by setting the sdk.ua.appId system property. + * If the property is already set and not empty, appends the Powertools user agent with a "/" separator. + * This should be called during library initialization to ensure the user agent is properly configured. + */ + public static void configureUserAgent(String ptFeature) { + try { + String existingValue = System.getProperty(SDK_USER_AGENT_APP_ID); + String powertoolsUserAgent = getUserAgent(ptFeature); + + if (existingValue != null && !existingValue.isEmpty()) { + System.setProperty(SDK_USER_AGENT_APP_ID, existingValue + "/" + powertoolsUserAgent); + } else { + System.setProperty(SDK_USER_AGENT_APP_ID, powertoolsUserAgent); + } + } catch (Exception e) { + // We don't re-raise since we don't want to break the user if something in this logic doesn't work + LOG.warn("Unable to configure user agent system property", e); + } + } + /** * Retrieves the user agent string for the Powertools for AWS Lambda. - * It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTEnv/{PT_EXEC_ENV} + * It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTENV/{PT_EXEC_ENV} * The version of the project is automatically retrieved. * The PT_EXEC_ENV is automatically retrieved from the AWS_EXECUTION_ENV environment variable. * If it AWS_EXECUTION_ENV is not set, PT_EXEC_ENV defaults to "NA" @@ -96,7 +114,6 @@ static String getVersionFromProperties(String propertyFileName, String versionKe * @return the user agent string */ public static String getUserAgent(String ptFeature) { - String awsExecutionEnv = getenv(AWS_EXECUTION_ENV); String ptExecEnv = awsExecutionEnv != null ? awsExecutionEnv : NA; String userAgent = USER_AGENT_PATTERN.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); @@ -105,7 +122,7 @@ public static String getUserAgent(String ptFeature) { ptFeature = NO_OP; } return userAgent - .replace(PT_FEATURE_VARIABLE, ptFeature) + .replace(PT_FEATURE_VARIABLE, ptFeature.toUpperCase(Locale.ROOT)) .replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); } } diff --git a/powertools-common/src/test/java/software/amazon/lambda/powertools/common/internal/UserAgentConfiguratorTest.java b/powertools-common/src/test/java/software/amazon/lambda/powertools/common/internal/UserAgentConfiguratorTest.java index 0c7935a55..fbe4529d8 100644 --- a/powertools-common/src/test/java/software/amazon/lambda/powertools/common/internal/UserAgentConfiguratorTest.java +++ b/powertools-common/src/test/java/software/amazon/lambda/powertools/common/internal/UserAgentConfiguratorTest.java @@ -31,11 +31,9 @@ class UserAgentConfiguratorTest { - private static final String SEM_VER_PATTERN = - "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"; + private static final String SEM_VER_PATTERN = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"; private static final String VERSION = UserAgentConfigurator.getProjectVersion(); - @Test void testGetVersion() { @@ -91,7 +89,7 @@ void testGetUserAgent() { assertThat(userAgent) .isNotNull() - .isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA"); + .isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/NA"); } @@ -101,7 +99,7 @@ void testGetUserAgent_NoFeature() { assertThat(userAgent) .isNotNull() - .isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); + .isEqualTo("PT/NO-OP/" + VERSION + " PTENV/NA"); } @Test @@ -110,7 +108,7 @@ void testGetUserAgent_NullFeature() { assertThat(userAgent) .isNotNull() - .isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); + .isEqualTo("PT/NO-OP/" + VERSION + " PTENV/NA"); } @Test @@ -120,7 +118,34 @@ void testGetUserAgent_SetAWSExecutionEnv() { assertThat(userAgent) .isNotNull() - .isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8"); + .isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/AWS_Lambda_java8"); + } + + @Test + void testConfigureUserAgent() { + System.clearProperty("sdk.ua.appId"); + UserAgentConfigurator.configureUserAgent("test-feature"); + + assertThat(System.getProperty("sdk.ua.appId")) + .isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/NA"); + } + + @Test + void testConfigureUserAgent_WithExistingValue() { + System.setProperty("sdk.ua.appId", "UserValueABC123"); + UserAgentConfigurator.configureUserAgent("test-feature"); + + assertThat(System.getProperty("sdk.ua.appId")) + .isEqualTo("UserValueABC123/PT/TEST-FEATURE/" + VERSION + " PTENV/NA"); + } + + @Test + void testConfigureUserAgent_WithEmptyExistingValue() { + System.setProperty("sdk.ua.appId", ""); + UserAgentConfigurator.configureUserAgent("test-feature"); + + assertThat(System.getProperty("sdk.ua.appId")) + .isEqualTo("PT/TEST-FEATURE/" + VERSION + " PTENV/NA"); } } diff --git a/powertools-idempotency/powertools-idempotency-dynamodb/pom.xml b/powertools-idempotency/powertools-idempotency-dynamodb/pom.xml index 191d75eeb..885c9c9cd 100644 --- a/powertools-idempotency/powertools-idempotency-dynamodb/pom.xml +++ b/powertools-idempotency/powertools-idempotency-dynamodb/pom.xml @@ -57,6 +57,10 @@ + + software.amazon.awssdk + sdk-core + org.crac crac @@ -94,6 +98,11 @@ 2.2.0 test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-idempotency/powertools-idempotency-dynamodb/src/main/java/software/amazon/lambda/powertools/idempotency/dynamodb/internal/IdempotencyDynamodbUserAgentInterceptor.java b/powertools-idempotency/powertools-idempotency-dynamodb/src/main/java/software/amazon/lambda/powertools/idempotency/dynamodb/internal/IdempotencyDynamodbUserAgentInterceptor.java new file mode 100644 index 000000000..98d7a7440 --- /dev/null +++ b/powertools-idempotency/powertools-idempotency-dynamodb/src/main/java/software/amazon/lambda/powertools/idempotency/dynamodb/internal/IdempotencyDynamodbUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.idempotency.dynamodb.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-idempotency-dynamodb module is on the classpath. + */ +public final class IdempotencyDynamodbUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("idempotency-dynamodb"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-idempotency-dynamodb/reflect-config.json b/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-idempotency-dynamodb/reflect-config.json index f0ba9c4c2..6d6fbceb3 100644 --- a/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-idempotency-dynamodb/reflect-config.json +++ b/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-idempotency-dynamodb/reflect-config.json @@ -321,5 +321,9 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"software.amazon.lambda.powertools.idempotency.dynamodb.internal.IdempotencyDynamodbUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..a04caa403 --- /dev/null +++ b/powertools-idempotency/powertools-idempotency-dynamodb/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.idempotency.dynamodb.internal.IdempotencyDynamodbUserAgentInterceptor diff --git a/powertools-idempotency/powertools-idempotency-dynamodb/src/test/java/software/amazon/lambda/powertools/idempotency/dynamodb/internal/IdempotencyDynamodbUserAgentInterceptorTest.java b/powertools-idempotency/powertools-idempotency-dynamodb/src/test/java/software/amazon/lambda/powertools/idempotency/dynamodb/internal/IdempotencyDynamodbUserAgentInterceptorTest.java new file mode 100644 index 000000000..e6940a760 --- /dev/null +++ b/powertools-idempotency/powertools-idempotency-dynamodb/src/test/java/software/amazon/lambda/powertools/idempotency/dynamodb/internal/IdempotencyDynamodbUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.idempotency.dynamodb.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class IdempotencyDynamodbUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/IDEMPOTENCY-DYNAMODB/"); + } +} diff --git a/powertools-kafka/pom.xml b/powertools-kafka/pom.xml index cac2706b7..65cd7051d 100644 --- a/powertools-kafka/pom.xml +++ b/powertools-kafka/pom.xml @@ -78,6 +78,16 @@ aws-lambda-java-serialization ${lambda-serialization.version} + + software.amazon.lambda + powertools-common + ${project.version} + + + software.amazon.awssdk + sdk-core + provided + @@ -120,6 +130,11 @@ assertj-core test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-kafka/src/main/java/software/amazon/lambda/powertools/kafka/internal/KafkaUserAgentInterceptor.java b/powertools-kafka/src/main/java/software/amazon/lambda/powertools/kafka/internal/KafkaUserAgentInterceptor.java new file mode 100644 index 000000000..2db4789b3 --- /dev/null +++ b/powertools-kafka/src/main/java/software/amazon/lambda/powertools/kafka/internal/KafkaUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.kafka.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-kafka module is on the classpath. + */ +public final class KafkaUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("kafka"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-kafka/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-kafka/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..1ce363ad9 --- /dev/null +++ b/powertools-kafka/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.kafka.internal.KafkaUserAgentInterceptor diff --git a/powertools-kafka/src/test/java/software/amazon/lambda/powertools/kafka/internal/KafkaUserAgentInterceptorTest.java b/powertools-kafka/src/test/java/software/amazon/lambda/powertools/kafka/internal/KafkaUserAgentInterceptorTest.java new file mode 100644 index 000000000..4323a42e9 --- /dev/null +++ b/powertools-kafka/src/test/java/software/amazon/lambda/powertools/kafka/internal/KafkaUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.kafka.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class KafkaUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/KAFKA/"); + } +} \ No newline at end of file diff --git a/powertools-large-messages/src/main/java/software/amazon/lambda/powertools/largemessages/internal/LargeMessagesUserAgentInterceptor.java b/powertools-large-messages/src/main/java/software/amazon/lambda/powertools/largemessages/internal/LargeMessagesUserAgentInterceptor.java new file mode 100644 index 000000000..87d179dd7 --- /dev/null +++ b/powertools-large-messages/src/main/java/software/amazon/lambda/powertools/largemessages/internal/LargeMessagesUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.largemessages.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-largemessages module is on the classpath. + */ +public final class LargeMessagesUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("large-messages"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-large-messages/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-large-messages/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..ab5a6f378 --- /dev/null +++ b/powertools-large-messages/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.largemessages.internal.LargeMessagesUserAgentInterceptor diff --git a/powertools-large-messages/src/test/java/software/amazon/lambda/powertools/largemessages/internal/LargeMessagesUserAgentInterceptorTest.java b/powertools-large-messages/src/test/java/software/amazon/lambda/powertools/largemessages/internal/LargeMessagesUserAgentInterceptorTest.java new file mode 100644 index 000000000..b32ee1176 --- /dev/null +++ b/powertools-large-messages/src/test/java/software/amazon/lambda/powertools/largemessages/internal/LargeMessagesUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.largemessages.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class LargeMessagesUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/LARGE-MESSAGES/"); + } +} \ No newline at end of file diff --git a/powertools-logging/powertools-logging-log4j/pom.xml b/powertools-logging/powertools-logging-log4j/pom.xml index 92283b0cf..2b85a3752 100644 --- a/powertools-logging/powertools-logging-log4j/pom.xml +++ b/powertools-logging/powertools-logging-log4j/pom.xml @@ -39,6 +39,11 @@ org.apache.logging.log4j log4j-layout-template-json + + software.amazon.awssdk + sdk-core + provided + @@ -93,6 +98,11 @@ test-jar test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/log4j/internal/Log4jUserAgentInterceptor.java b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/log4j/internal/Log4jUserAgentInterceptor.java new file mode 100644 index 000000000..510ee858c --- /dev/null +++ b/powertools-logging/powertools-logging-log4j/src/main/java/software/amazon/lambda/powertools/logging/log4j/internal/Log4jUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.logging.log4j.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-logging-log4j module is on the classpath. + */ +public final class Log4jUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("logging-log4j"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/reflect-config.json b/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/reflect-config.json index adbd9e0c1..6cbbee583 100644 --- a/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/reflect-config.json +++ b/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/reflect-config.json @@ -1083,5 +1083,9 @@ "name":"software.amazon.lambda.powertools.logging.log4j.BufferingAppender", "queryAllDeclaredMethods":true, "methods":[{"name":"createAppender","parameterTypes":["java.lang.String","org.apache.logging.log4j.core.Filter","org.apache.logging.log4j.core.Layout","org.apache.logging.log4j.core.config.AppenderRef[]","org.apache.logging.log4j.core.config.Configuration","java.lang.String","int","boolean"] }] +}, +{ + "name":"software.amazon.lambda.powertools.logging.log4j.internal.Log4jUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/resource-config.json b/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/resource-config.json index cf017fdeb..a4bcd55fa 100644 --- a/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/resource-config.json +++ b/powertools-logging/powertools-logging-log4j/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-log4j/resource-config.json @@ -34,6 +34,8 @@ "pattern":"\\QMETA-INF/services/software.amazon.lambda.powertools.logging.internal.LoggingManager\\E" }, { "pattern":"\\QStackTraceElementLayout.json\\E" + }, { + "pattern":"\\Qsoftware/amazon/awssdk/global/handlers/execution.interceptors\\E" }]}, "bundles":[] } diff --git a/powertools-logging/powertools-logging-log4j/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-logging/powertools-logging-log4j/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..22150f4b7 --- /dev/null +++ b/powertools-logging/powertools-logging-log4j/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.logging.log4j.internal.Log4jUserAgentInterceptor diff --git a/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/log4j/internal/Log4jUserAgentInterceptorTest.java b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/log4j/internal/Log4jUserAgentInterceptorTest.java new file mode 100644 index 000000000..77d5b06e3 --- /dev/null +++ b/powertools-logging/powertools-logging-log4j/src/test/java/software/amazon/lambda/powertools/logging/log4j/internal/Log4jUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.logging.log4j.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class Log4jUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/LOGGING-LOG4J/"); + } +} diff --git a/powertools-logging/powertools-logging-logback/pom.xml b/powertools-logging/powertools-logging-logback/pom.xml index ff0312001..17e39dda7 100644 --- a/powertools-logging/powertools-logging-logback/pom.xml +++ b/powertools-logging/powertools-logging-logback/pom.xml @@ -36,6 +36,11 @@ + + software.amazon.awssdk + sdk-core + provided + @@ -90,6 +95,11 @@ junit-pioneer test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/internal/LogbackUserAgentInterceptor.java b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/internal/LogbackUserAgentInterceptor.java new file mode 100644 index 000000000..c35171a01 --- /dev/null +++ b/powertools-logging/powertools-logging-logback/src/main/java/software/amazon/lambda/powertools/logging/logback/internal/LogbackUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.logging.logback.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-logging-logback module is on the classpath. + */ +public final class LogbackUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("logging-logback"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/reflect-config.json b/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/reflect-config.json index dfc50427f..d4f4a4d7d 100644 --- a/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/reflect-config.json +++ b/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/reflect-config.json @@ -179,5 +179,9 @@ "name":"software.amazon.lambda.powertools.logging.logback.LambdaJsonEncoder", "queryAllPublicMethods":true, "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"software.amazon.lambda.powertools.logging.logback.internal.LogbackUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/resource-config.json b/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/resource-config.json index 33d1d61c4..b60a39ad5 100644 --- a/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/resource-config.json +++ b/powertools-logging/powertools-logging-logback/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-logging-logback/resource-config.json @@ -10,6 +10,8 @@ "pattern":"\\QMETA-INF/services/org.slf4j.spi.SLF4JServiceProvider\\E" }, { "pattern":"\\QMETA-INF/services/software.amazon.lambda.powertools.logging.internal.LoggingManager\\E" + }, { + "pattern":"\\Qsoftware/amazon/awssdk/global/handlers/execution.interceptors\\E" }]}, "bundles":[] } diff --git a/powertools-logging/powertools-logging-logback/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-logging/powertools-logging-logback/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..1ce49119f --- /dev/null +++ b/powertools-logging/powertools-logging-logback/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.logging.logback.internal.LogbackUserAgentInterceptor diff --git a/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/logback/internal/LogbackUserAgentInterceptorTest.java b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/logback/internal/LogbackUserAgentInterceptorTest.java new file mode 100644 index 000000000..622343668 --- /dev/null +++ b/powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/logback/internal/LogbackUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.logging.logback.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class LogbackUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/LOGGING-LOGBACK/"); + } +} diff --git a/powertools-metrics/pom.xml b/powertools-metrics/pom.xml index c1ac723f1..58eab8a45 100644 --- a/powertools-metrics/pom.xml +++ b/powertools-metrics/pom.xml @@ -73,6 +73,11 @@ org.apache.commons commons-lang3 + + software.amazon.awssdk + sdk-core + provided + @@ -117,6 +122,11 @@ test-jar test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-metrics/src/main/java/software/amazon/lambda/powertools/metrics/internal/MetricsUserAgentInterceptor.java b/powertools-metrics/src/main/java/software/amazon/lambda/powertools/metrics/internal/MetricsUserAgentInterceptor.java new file mode 100644 index 000000000..5a466cc3a --- /dev/null +++ b/powertools-metrics/src/main/java/software/amazon/lambda/powertools/metrics/internal/MetricsUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.metrics.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the metrics module is on the classpath. + */ +public final class MetricsUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("metrics"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/reflect-config.json b/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/reflect-config.json index 43b2822d6..533335782 100644 --- a/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/reflect-config.json +++ b/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/reflect-config.json @@ -148,5 +148,9 @@ "name": "software.amazon.lambda.powertools.metrics.provider.MetricsProvider", "allDeclaredClasses": true, "queryAllPublicMethods": true + }, + { + "name": "software.amazon.lambda.powertools.metrics.internal.MetricsUserAgentInterceptor", + "methods": [{ "name": "", "parameterTypes": [] }] } ] diff --git a/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/resource-config.json b/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/resource-config.json index d47298855..0667ee26a 100644 --- a/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/resource-config.json +++ b/powertools-metrics/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-metrics/resource-config.json @@ -6,6 +6,9 @@ }, { "pattern": "\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E" + }, + { + "pattern": "\\Qsoftware/amazon/awssdk/global/handlers/execution.interceptors\\E" } ] }, diff --git a/powertools-metrics/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-metrics/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..38e53da3e --- /dev/null +++ b/powertools-metrics/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.metrics.internal.MetricsUserAgentInterceptor diff --git a/powertools-metrics/src/test/java/software/amazon/lambda/powertools/metrics/internal/MetricsUserAgentInterceptorTest.java b/powertools-metrics/src/test/java/software/amazon/lambda/powertools/metrics/internal/MetricsUserAgentInterceptorTest.java new file mode 100644 index 000000000..673f9f7d4 --- /dev/null +++ b/powertools-metrics/src/test/java/software/amazon/lambda/powertools/metrics/internal/MetricsUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.metrics.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class MetricsUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/METRICS/"); + } +} diff --git a/powertools-parameters/powertools-parameters-appconfig/pom.xml b/powertools-parameters/powertools-parameters-appconfig/pom.xml index bbb6a1111..b2c4f3426 100644 --- a/powertools-parameters/powertools-parameters-appconfig/pom.xml +++ b/powertools-parameters/powertools-parameters-appconfig/pom.xml @@ -35,6 +35,10 @@ + + software.amazon.awssdk + sdk-core + org.aspectj aspectjrt @@ -82,6 +86,11 @@ aspectjweaver test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-parameters/powertools-parameters-appconfig/src/main/java/software/amazon/lambda/powertools/parameters/appconfig/internal/ParametersAppconfigUserAgentInterceptor.java b/powertools-parameters/powertools-parameters-appconfig/src/main/java/software/amazon/lambda/powertools/parameters/appconfig/internal/ParametersAppconfigUserAgentInterceptor.java new file mode 100644 index 000000000..01fc8d096 --- /dev/null +++ b/powertools-parameters/powertools-parameters-appconfig/src/main/java/software/amazon/lambda/powertools/parameters/appconfig/internal/ParametersAppconfigUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.appconfig.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-parameters-appconfig module is on the classpath. + */ +public final class ParametersAppconfigUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("parameters-appconfig"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-parameters/powertools-parameters-appconfig/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-appconfig/reflect-config.json b/powertools-parameters/powertools-parameters-appconfig/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-appconfig/reflect-config.json index 7e7b40197..b9ae934d6 100644 --- a/powertools-parameters/powertools-parameters-appconfig/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-appconfig/reflect-config.json +++ b/powertools-parameters/powertools-parameters-appconfig/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-appconfig/reflect-config.json @@ -361,5 +361,9 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"software.amazon.lambda.powertools.parameters.appconfig.internal.ParametersAppconfigUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-parameters/powertools-parameters-appconfig/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-parameters/powertools-parameters-appconfig/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..c37ecc083 --- /dev/null +++ b/powertools-parameters/powertools-parameters-appconfig/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.parameters.appconfig.internal.ParametersAppconfigUserAgentInterceptor diff --git a/powertools-parameters/powertools-parameters-appconfig/src/test/java/software/amazon/lambda/powertools/parameters/appconfig/internal/ParametersAppconfigUserAgentInterceptorTest.java b/powertools-parameters/powertools-parameters-appconfig/src/test/java/software/amazon/lambda/powertools/parameters/appconfig/internal/ParametersAppconfigUserAgentInterceptorTest.java new file mode 100644 index 000000000..124b71ef3 --- /dev/null +++ b/powertools-parameters/powertools-parameters-appconfig/src/test/java/software/amazon/lambda/powertools/parameters/appconfig/internal/ParametersAppconfigUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.appconfig.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class ParametersAppconfigUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/PARAMETERS-APPCONFIG/"); + } +} \ No newline at end of file diff --git a/powertools-parameters/powertools-parameters-dynamodb/pom.xml b/powertools-parameters/powertools-parameters-dynamodb/pom.xml index fa969e585..e03227eb8 100644 --- a/powertools-parameters/powertools-parameters-dynamodb/pom.xml +++ b/powertools-parameters/powertools-parameters-dynamodb/pom.xml @@ -36,6 +36,10 @@ + + software.amazon.awssdk + sdk-core + org.aspectj aspectjrt @@ -83,6 +87,11 @@ aspectjweaver test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-parameters/powertools-parameters-dynamodb/src/main/java/software/amazon/lambda/powertools/parameters/dynamodb/internal/ParametersDynamodbUserAgentInterceptor.java b/powertools-parameters/powertools-parameters-dynamodb/src/main/java/software/amazon/lambda/powertools/parameters/dynamodb/internal/ParametersDynamodbUserAgentInterceptor.java new file mode 100644 index 000000000..0b8b01dcb --- /dev/null +++ b/powertools-parameters/powertools-parameters-dynamodb/src/main/java/software/amazon/lambda/powertools/parameters/dynamodb/internal/ParametersDynamodbUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.dynamodb.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-parameters-dynamodb module is on the classpath. + */ +public final class ParametersDynamodbUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("parameters-dynamodb"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-dynamodb/reflect-config.json b/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-dynamodb/reflect-config.json index 77e953aac..e49454b83 100644 --- a/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-dynamodb/reflect-config.json +++ b/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-dynamodb/reflect-config.json @@ -322,5 +322,9 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"software.amazon.lambda.powertools.parameters.dynamodb.internal.ParametersDynamodbUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..f7de6e9be --- /dev/null +++ b/powertools-parameters/powertools-parameters-dynamodb/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.parameters.dynamodb.internal.ParametersDynamodbUserAgentInterceptor diff --git a/powertools-parameters/powertools-parameters-dynamodb/src/test/java/software/amazon/lambda/powertools/parameters/dynamodb/internal/ParametersDynamodbUserAgentInterceptorTest.java b/powertools-parameters/powertools-parameters-dynamodb/src/test/java/software/amazon/lambda/powertools/parameters/dynamodb/internal/ParametersDynamodbUserAgentInterceptorTest.java new file mode 100644 index 000000000..f9c8ebea5 --- /dev/null +++ b/powertools-parameters/powertools-parameters-dynamodb/src/test/java/software/amazon/lambda/powertools/parameters/dynamodb/internal/ParametersDynamodbUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.dynamodb.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class ParametersDynamodbUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/PARAMETERS-DYNAMODB/"); + } +} \ No newline at end of file diff --git a/powertools-parameters/powertools-parameters-secrets/pom.xml b/powertools-parameters/powertools-parameters-secrets/pom.xml index 55c254f88..6a576f529 100644 --- a/powertools-parameters/powertools-parameters-secrets/pom.xml +++ b/powertools-parameters/powertools-parameters-secrets/pom.xml @@ -36,6 +36,10 @@ + + software.amazon.awssdk + sdk-core + org.aspectj aspectjrt @@ -83,6 +87,11 @@ aspectjweaver test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-parameters/powertools-parameters-secrets/src/main/java/software/amazon/lambda/powertools/parameters/secrets/internal/ParametersSecretsUserAgentInterceptor.java b/powertools-parameters/powertools-parameters-secrets/src/main/java/software/amazon/lambda/powertools/parameters/secrets/internal/ParametersSecretsUserAgentInterceptor.java new file mode 100644 index 000000000..e3eda5889 --- /dev/null +++ b/powertools-parameters/powertools-parameters-secrets/src/main/java/software/amazon/lambda/powertools/parameters/secrets/internal/ParametersSecretsUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.secrets.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-parameters-secrets module is on the classpath. + */ +public final class ParametersSecretsUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("parameters-secrets"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-parameters/powertools-parameters-secrets/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-secrets/reflect-config.json b/powertools-parameters/powertools-parameters-secrets/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-secrets/reflect-config.json index 7dfaf1b03..097a30784 100644 --- a/powertools-parameters/powertools-parameters-secrets/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-secrets/reflect-config.json +++ b/powertools-parameters/powertools-parameters-secrets/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-secrets/reflect-config.json @@ -319,5 +319,9 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"software.amazon.lambda.powertools.parameters.secrets.internal.ParametersSecretsUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-parameters/powertools-parameters-secrets/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-parameters/powertools-parameters-secrets/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..ca08369c5 --- /dev/null +++ b/powertools-parameters/powertools-parameters-secrets/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.parameters.secrets.internal.ParametersSecretsUserAgentInterceptor diff --git a/powertools-parameters/powertools-parameters-secrets/src/test/java/software/amazon/lambda/powertools/parameters/secrets/internal/ParametersSecretsUserAgentInterceptorTest.java b/powertools-parameters/powertools-parameters-secrets/src/test/java/software/amazon/lambda/powertools/parameters/secrets/internal/ParametersSecretsUserAgentInterceptorTest.java new file mode 100644 index 000000000..6d59ff717 --- /dev/null +++ b/powertools-parameters/powertools-parameters-secrets/src/test/java/software/amazon/lambda/powertools/parameters/secrets/internal/ParametersSecretsUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.secrets.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class ParametersSecretsUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/PARAMETERS-SECRETS/"); + } +} \ No newline at end of file diff --git a/powertools-parameters/powertools-parameters-ssm/pom.xml b/powertools-parameters/powertools-parameters-ssm/pom.xml index d1dc88d84..7758fd906 100644 --- a/powertools-parameters/powertools-parameters-ssm/pom.xml +++ b/powertools-parameters/powertools-parameters-ssm/pom.xml @@ -36,6 +36,10 @@ + + software.amazon.awssdk + sdk-core + org.aspectj aspectjrt @@ -83,6 +87,11 @@ aspectjweaver test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-parameters/powertools-parameters-ssm/src/main/java/software/amazon/lambda/powertools/parameters/ssm/internal/ParametersSsmUserAgentInterceptor.java b/powertools-parameters/powertools-parameters-ssm/src/main/java/software/amazon/lambda/powertools/parameters/ssm/internal/ParametersSsmUserAgentInterceptor.java new file mode 100644 index 000000000..ad1ff65dc --- /dev/null +++ b/powertools-parameters/powertools-parameters-ssm/src/main/java/software/amazon/lambda/powertools/parameters/ssm/internal/ParametersSsmUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.ssm.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-parameters-ssm module is on the classpath. + */ +public final class ParametersSsmUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("parameters-ssm"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-parameters/powertools-parameters-ssm/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-ssm/reflect-config.json b/powertools-parameters/powertools-parameters-ssm/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-ssm/reflect-config.json index 5bc2deb4a..a655e62ce 100644 --- a/powertools-parameters/powertools-parameters-ssm/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-ssm/reflect-config.json +++ b/powertools-parameters/powertools-parameters-ssm/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-parameters-ssm/reflect-config.json @@ -337,5 +337,9 @@ { "name":"sun.security.x509.SubjectKeyIdentifierExtension", "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }] +}, +{ + "name":"software.amazon.lambda.powertools.parameters.ssm.internal.ParametersSsmUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-parameters/powertools-parameters-ssm/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-parameters/powertools-parameters-ssm/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..4cce863f6 --- /dev/null +++ b/powertools-parameters/powertools-parameters-ssm/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.parameters.ssm.internal.ParametersSsmUserAgentInterceptor diff --git a/powertools-parameters/powertools-parameters-ssm/src/test/java/software/amazon/lambda/powertools/parameters/ssm/internal/ParametersSsmUserAgentInterceptorTest.java b/powertools-parameters/powertools-parameters-ssm/src/test/java/software/amazon/lambda/powertools/parameters/ssm/internal/ParametersSsmUserAgentInterceptorTest.java new file mode 100644 index 000000000..8f6db7e21 --- /dev/null +++ b/powertools-parameters/powertools-parameters-ssm/src/test/java/software/amazon/lambda/powertools/parameters/ssm/internal/ParametersSsmUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.parameters.ssm.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class ParametersSsmUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/PARAMETERS-SSM/"); + } +} \ No newline at end of file diff --git a/powertools-tracing/pom.xml b/powertools-tracing/pom.xml index 6081abd66..045e76cbf 100644 --- a/powertools-tracing/pom.xml +++ b/powertools-tracing/pom.xml @@ -46,6 +46,10 @@ software.amazon.awssdk aws-core + + software.amazon.awssdk + sdk-core + com.amazonaws aws-lambda-java-core @@ -118,6 +122,11 @@ assertj-core test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/TracingUserAgentInterceptor.java b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/TracingUserAgentInterceptor.java new file mode 100644 index 000000000..489243517 --- /dev/null +++ b/powertools-tracing/src/main/java/software/amazon/lambda/powertools/tracing/internal/TracingUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.tracing.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-tracing module is on the classpath. + */ +public final class TracingUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("tracing"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/reflect-config.json b/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/reflect-config.json index 94a514dee..a71154276 100644 --- a/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/reflect-config.json +++ b/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/reflect-config.json @@ -361,5 +361,9 @@ { "name":"sun.security.provider.SHA", "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"software.amazon.lambda.powertools.tracing.internal.TracingUserAgentInterceptor", + "methods":[{"name":"","parameterTypes":[] }] } ] diff --git a/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/resource-config.json b/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/resource-config.json index 2ac72d18f..64408b8b6 100644 --- a/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/resource-config.json +++ b/powertools-tracing/src/main/resources/META-INF/native-image/software.amazon.lambda/powertools-tracing/resource-config.json @@ -26,6 +26,8 @@ "pattern":"\\Qcommons-logging.properties\\E" }, { "pattern":"\\Qorg/slf4j/impl/StaticLoggerBinder.class\\E" + }, { + "pattern":"\\Qsoftware/amazon/awssdk/global/handlers/execution.interceptors\\E" }]}, "bundles":[] } diff --git a/powertools-tracing/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-tracing/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..5f15a8000 --- /dev/null +++ b/powertools-tracing/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.tracing.internal.TracingUserAgentInterceptor diff --git a/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/internal/TracingUserAgentInterceptorTest.java b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/internal/TracingUserAgentInterceptorTest.java new file mode 100644 index 000000000..b24f6c6f7 --- /dev/null +++ b/powertools-tracing/src/test/java/software/amazon/lambda/powertools/tracing/internal/TracingUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.tracing.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class TracingUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/TRACING/"); + } +} \ No newline at end of file diff --git a/powertools-validation/pom.xml b/powertools-validation/pom.xml index 1c048e66a..6ecee16a1 100644 --- a/powertools-validation/pom.xml +++ b/powertools-validation/pom.xml @@ -75,6 +75,11 @@ org.crac crac + + software.amazon.awssdk + sdk-core + provided + @@ -122,6 +127,11 @@ junit-jupiter-params test + + software.amazon.awssdk + s3 + test + diff --git a/powertools-validation/src/main/java/software/amazon/lambda/powertools/validation/internal/ValidationUserAgentInterceptor.java b/powertools-validation/src/main/java/software/amazon/lambda/powertools/validation/internal/ValidationUserAgentInterceptor.java new file mode 100644 index 000000000..ee92ff367 --- /dev/null +++ b/powertools-validation/src/main/java/software/amazon/lambda/powertools/validation/internal/ValidationUserAgentInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.validation.internal; + +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator; + +/** + * Global interceptor that configures the User-Agent for all AWS SDK clients + * when the powertools-validation module is on the classpath. + */ +public final class ValidationUserAgentInterceptor implements ExecutionInterceptor { + static { + UserAgentConfigurator.configureUserAgent("validation"); + } + + @Override + public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { + // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is + // loaded by AWS SDK Global Interceptors. + return context.request(); + } +} diff --git a/powertools-validation/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors b/powertools-validation/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors new file mode 100644 index 000000000..bcaa3fabf --- /dev/null +++ b/powertools-validation/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors @@ -0,0 +1 @@ +software.amazon.lambda.powertools.validation.internal.ValidationUserAgentInterceptor diff --git a/powertools-validation/src/test/java/software/amazon/lambda/powertools/validation/internal/ValidationUserAgentInterceptorTest.java b/powertools-validation/src/test/java/software/amazon/lambda/powertools/validation/internal/ValidationUserAgentInterceptorTest.java new file mode 100644 index 000000000..9bacf33f9 --- /dev/null +++ b/powertools-validation/src/test/java/software/amazon/lambda/powertools/validation/internal/ValidationUserAgentInterceptorTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package software.amazon.lambda.powertools.validation.internal; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.assertj.core.api.Assertions.assertThat; + +class ValidationUserAgentInterceptorTest { + + @Test + void shouldConfigureUserAgentWhenCreatingAwsSdkClient() { + // WHEN creating an AWS SDK client, the interceptor should be loaded + // We use S3 client but it can be any arbitrary AWS SDK client + S3Client.builder().region(Region.US_EAST_1).build(); + + // THEN the user agent system property should be set + String userAgent = System.getProperty("sdk.ua.appId"); + assertThat(userAgent).contains("PT/VALIDATION/"); + } +}