diff --git a/spring-cloud-aws-autoconfigure/pom.xml b/spring-cloud-aws-autoconfigure/pom.xml
index d4131c45c..1ce9c13e5 100644
--- a/spring-cloud-aws-autoconfigure/pom.xml
+++ b/spring-cloud-aws-autoconfigure/pom.xml
@@ -75,6 +75,11 @@
s3-transfer-manager
true
+
+ software.amazon.awssdk
+ cloudwatch-metric-publisher
+ true
+
io.awspring.cloud
spring-cloud-aws-s3-cross-region-client
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/AwsClientProperties.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/AwsClientProperties.java
index 6bee7a541..a7c85207e 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/AwsClientProperties.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/AwsClientProperties.java
@@ -15,6 +15,7 @@
*/
package io.awspring.cloud.autoconfigure;
+import io.awspring.cloud.autoconfigure.core.CloudWatchMetricsPublisherProperties;
import java.net.URI;
import org.springframework.lang.Nullable;
@@ -37,6 +38,12 @@ public abstract class AwsClientProperties {
@Nullable
private String region;
+ /**
+ * Overrides the global enablement of the CloudWatch MetricsPublisher.
+ */
+ @Nullable
+ private CloudWatchMetricsPublisherProperties metrics;
+
@Nullable
public URI getEndpoint() {
return this.endpoint;
@@ -54,4 +61,13 @@ public String getRegion() {
public void setRegion(String region) {
this.region = region;
}
+
+ @Nullable
+ public CloudWatchMetricsPublisherProperties getMetrics() {
+ return metrics;
+ }
+
+ public void setMetrics(@Nullable CloudWatchMetricsPublisherProperties metrics) {
+ this.metrics = metrics;
+ }
}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/AbstractAwsConfigDataLocationResolver.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/AbstractAwsConfigDataLocationResolver.java
index 50a32999b..0c000c9a4 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/AbstractAwsConfigDataLocationResolver.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/AbstractAwsConfigDataLocationResolver.java
@@ -22,6 +22,8 @@
import io.awspring.cloud.autoconfigure.core.RegionProperties;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import io.awspring.cloud.core.SpringCloudClientConfiguration;
+import java.net.URI;
+import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -34,14 +36,19 @@
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
import org.springframework.boot.context.config.ConfigDataResource;
import org.springframework.boot.context.config.ConfigDataResourceNotFoundException;
+import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
+import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
+import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
/**
* Base class for AWS specific {@link ConfigDataLocationResolver}s.
@@ -55,6 +62,10 @@ public abstract class AbstractAwsConfigDataLocationResolver> CloudWatchMetricPublisher createMetricPublisher(
+ AwsProperties awsProperties, AwsClientProperties awsClientProperties, AwsRegionProvider regionProvider,
+ T clientBuilder, AwsCredentialsProvider credentialsProvider) {
+ CloudWatchMetricPublisher.Builder builder = CloudWatchMetricPublisher.builder();
+ PropertyMapper map = PropertyMapper.get();
+ if ((awsClientProperties.getMetrics() != null && awsClientProperties.getMetrics().getEnabled())) {
+ CloudWatchAsyncClient cloudwatchAsyncClient = createCloudwatchAsyncClient(awsClientProperties.getRegion(),
+ awsClientProperties.getEndpoint(), credentialsProvider);
+
+ map.from(awsClientProperties.getMetrics()::getNamespace).whenNonNull().to(builder::namespace);
+ map.from(awsClientProperties.getMetrics()::getUploadFrequencyInSeconds).whenNonNull()
+ .to(v -> builder.uploadFrequency(Duration.ofSeconds(v)));
+ builder.cloudWatchClient(cloudwatchAsyncClient);
+ }
+ else if (awsProperties.getMetrics() == null
+ || (awsProperties.getMetrics() != null && awsProperties.getMetrics().getEnabled())) {
+ CloudWatchAsyncClient cloudwatchAsyncClient = createCloudwatchAsyncClient(regionProvider.getRegion().id(),
+ awsProperties.getEndpoint(), credentialsProvider);
+ if (awsProperties.getMetrics() != null) {
+ map.from(awsProperties.getMetrics()::getNamespace).whenNonNull().to(builder::namespace);
+ map.from(awsProperties.getMetrics()::getUploadFrequencyInSeconds).whenNonNull()
+ .to(v -> builder.uploadFrequency(Duration.ofSeconds(v)));
+ }
+ builder.cloudWatchClient(cloudwatchAsyncClient);
+ }
+ return builder.build();
+ }
+
+ private > CloudWatchAsyncClient createCloudwatchAsyncClient(String region,
+ URI endpoint, AwsCredentialsProvider credentialsProvider) {
+ return CloudWatchAsyncClient.builder().region(Region.of(region)).endpointOverride(endpoint)
+ .credentialsProvider(credentialsProvider).build();
+ }
}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLocationResolver.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLocationResolver.java
index 569c47d53..311c7872c 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLocationResolver.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLocationResolver.java
@@ -60,12 +60,15 @@ protected String getPrefix() {
public List resolveProfileSpecific(
ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, Profiles profiles)
throws ConfigDataLocationNotFoundException {
- registerBean(resolverContext, AwsProperties.class, loadAwsProperties(resolverContext.getBinder()));
- registerBean(resolverContext, ParameterStoreProperties.class, loadProperties(resolverContext.getBinder()));
+ AwsProperties awsProperties = loadAwsProperties(resolverContext.getBinder());
+ ParameterStoreProperties parameterStoreProperties = loadProperties(resolverContext.getBinder());
+ RegionProperties regionProperties = loadRegionProperties(resolverContext.getBinder());
+
+ registerBean(resolverContext, AwsProperties.class, awsProperties);
+ registerBean(resolverContext, ParameterStoreProperties.class, parameterStoreProperties);
registerBean(resolverContext, CredentialsProperties.class,
loadCredentialsProperties(resolverContext.getBinder()));
- registerBean(resolverContext, RegionProperties.class, loadRegionProperties(resolverContext.getBinder()));
-
+ registerBean(resolverContext, RegionProperties.class, regionProperties);
registerAndPromoteBean(resolverContext, SsmClient.class, this::createSimpleSystemManagementClient);
ParameterStorePropertySources sources = new ParameterStorePropertySources();
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLocationResolver.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLocationResolver.java
index 4c40cff61..76fe08a00 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLocationResolver.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLocationResolver.java
@@ -69,9 +69,7 @@ public List resolveProfileSpecific(
registerBean(resolverContext, CredentialsProperties.class,
loadCredentialsProperties(resolverContext.getBinder()));
registerBean(resolverContext, RegionProperties.class, loadRegionProperties(resolverContext.getBinder()));
-
registerAndPromoteBean(resolverContext, SecretsManagerClient.class, this::createAwsSecretsManagerClient);
-
SecretsManagerPropertySources propertySources = new SecretsManagerPropertySources();
List contexts = getCustomContexts(location.getNonPrefixedValue(PREFIX));
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsClientBuilderConfigurer.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsClientBuilderConfigurer.java
index f55569c2f..e0f2c75a5 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsClientBuilderConfigurer.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsClientBuilderConfigurer.java
@@ -16,16 +16,24 @@
package io.awspring.cloud.autoconfigure.core;
import io.awspring.cloud.autoconfigure.AwsClientProperties;
+import io.awspring.cloud.autoconfigure.metrics.CloudWatchProperties;
import io.awspring.cloud.core.SpringCloudClientConfiguration;
+import java.time.Duration;
import java.util.Optional;
+import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
+import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
+import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClientBuilder;
/**
* Provides a convenience method to apply common configuration to any {@link AwsClientBuilder}.
@@ -34,6 +42,8 @@
* @since 3.0
*/
public class AwsClientBuilderConfigurer {
+ public static final boolean IS_CLOUDWATCH_METRIC_PUBLISHER_PRESENT = ClassUtils
+ .isPresent("software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher", null);
private final AwsCredentialsProvider credentialsProvider;
private final AwsRegionProvider regionProvider;
private final AwsProperties awsProperties;
@@ -48,16 +58,20 @@ public class AwsClientBuilderConfigurer {
}
public > T configure(T builder) {
- return configure(builder, null, null);
+ return configure(builder, null, null, null);
}
public > T configure(T builder, @Nullable AwsClientProperties clientProperties,
- @Nullable AwsClientCustomizer customizer) {
+ @Nullable AwsClientCustomizer customizer, @Nullable MetricPublisher metricPublisher) {
+ ClientOverrideConfiguration.Builder clientOverrideConfigurationBuilder = clientOverrideConfiguration
+ .toBuilder();
Assert.notNull(builder, "builder is required");
Assert.notNull(clientProperties, "clientProperties are required");
-
+ if (metricPublisher != null) {
+ clientOverrideConfigurationBuilder.addMetricPublisher(metricPublisher).build();
+ }
builder.credentialsProvider(this.credentialsProvider).region(resolveRegion(clientProperties))
- .overrideConfiguration(this.clientOverrideConfiguration);
+ .overrideConfiguration(clientOverrideConfigurationBuilder.build());
Optional.ofNullable(this.awsProperties.getEndpoint()).ifPresent(builder::endpointOverride);
Optional.ofNullable(clientProperties).map(AwsClientProperties::getEndpoint)
.ifPresent(builder::endpointOverride);
@@ -68,6 +82,7 @@ public class AwsClientBuilderConfigurer {
if (customizer != null) {
AwsClientCustomizer.apply(customizer, builder);
}
+
return builder;
}
@@ -76,4 +91,33 @@ public Region resolveRegion(@Nullable AwsClientProperties clientProperties) {
? Region.of(clientProperties.getRegion())
: this.regionProvider.getRegion();
}
+
+ public static @Nullable MetricPublisher createSpecificMetricPublisher(MetricPublisher metricPublisher,
+ AwsClientProperties properties, AwsClientBuilderConfigurer awsClientBuilderConfigurer) {
+
+ if (IS_CLOUDWATCH_METRIC_PUBLISHER_PRESENT && properties.getMetrics() != null) {
+ if (properties.getMetrics().getEnabled()) {
+ PropertyMapper propertyMapper = PropertyMapper.get();
+
+ CloudWatchAsyncClientBuilder cloudWatchAsyncClientBuilder = CloudWatchAsyncClient.builder();
+ CloudWatchProperties cloudWatchProperties = new CloudWatchProperties();
+ propertyMapper.from(properties.getEndpoint()).whenNonNull().to(cloudWatchProperties::setEndpoint);
+ propertyMapper.from(properties.getRegion()).whenNonNull().to(cloudWatchProperties::setRegion);
+ CloudWatchAsyncClient cloudWatchAsyncClient = awsClientBuilderConfigurer
+ .configure(cloudWatchAsyncClientBuilder, cloudWatchProperties, null, null).build();
+
+ CloudWatchMetricPublisher.Builder builder = CloudWatchMetricPublisher.builder();
+ builder.cloudWatchClient(cloudWatchAsyncClient);
+ propertyMapper.from(properties.getMetrics()::getNamespace).whenNonNull().to(builder::namespace);
+ propertyMapper.from(properties.getMetrics()::getUploadFrequencyInSeconds).whenNonNull()
+ .to(v -> builder.uploadFrequency(Duration.ofSeconds(v)));
+ return builder.build();
+ }
+ else {
+ return null;
+ }
+
+ }
+ return metricPublisher;
+ }
}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsProperties.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsProperties.java
index 014ca6834..62e8d606f 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsProperties.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/AwsProperties.java
@@ -19,6 +19,7 @@
import java.net.URI;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.lang.Nullable;
import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode;
@@ -54,6 +55,13 @@ public class AwsProperties {
@Nullable
private Boolean dualstackEnabled;
+ /**
+ * Configure metrics properties to send to CloudWatch if needed
+ */
+ @NestedConfigurationProperty
+ @Nullable
+ private CloudWatchMetricsPublisherProperties metrics;
+
/**
* Configure whether the SDK should use the AWS fips endpoints.
*/
@@ -95,4 +103,13 @@ public Boolean getFipsEnabled() {
public void setFipsEnabled(@Nullable Boolean fipsEnabled) {
this.fipsEnabled = fipsEnabled;
}
+
+ @Nullable
+ public CloudWatchMetricsPublisherProperties getMetrics() {
+ return metrics;
+ }
+
+ public void setMetrics(@Nullable CloudWatchMetricsPublisherProperties metrics) {
+ this.metrics = metrics;
+ }
}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherAutoConfiguration.java
new file mode 100644
index 000000000..6729cec4b
--- /dev/null
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherAutoConfiguration.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013-2022 the original author or authors.
+ *
+ * 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
+ *
+ * https://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 io.awspring.cloud.autoconfigure.core;
+
+import io.awspring.cloud.autoconfigure.metrics.CloudWatchProperties;
+import java.time.Duration;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.context.properties.PropertyMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+import software.amazon.awssdk.regions.providers.AwsRegionProvider;
+import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
+import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClientBuilder;
+
+@Configuration(proxyBeanMethods = false)
+@EnableConfigurationProperties(AwsProperties.class)
+@ConditionalOnClass({ CloudWatchMetricPublisher.class })
+@AutoConfigureAfter({ CredentialsProviderAutoConfiguration.class, RegionProviderAutoConfiguration.class })
+public class CloudWatchMetricsPublisherAutoConfiguration {
+
+ private final AwsProperties awsProperties;
+
+ public CloudWatchMetricsPublisherAutoConfiguration(AwsProperties awsProperties) {
+ this.awsProperties = awsProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(name = "spring.cloud.aws.metrics.enabled", havingValue = "true", matchIfMissing = true)
+ MetricPublisher cloudWatchMetricPublisher(AwsClientBuilderConfigurer awsClientBuilderConfigurer,
+ AwsRegionProvider awsRegionProvider,
+ ObjectProvider> configurer) {
+ PropertyMapper propertyMapper = PropertyMapper.get();
+
+ CloudWatchAsyncClientBuilder cloudWatchAsyncClientBuilder = CloudWatchAsyncClient.builder();
+ CloudWatchProperties cloudWatchProperties = new CloudWatchProperties();
+ propertyMapper.from(awsProperties.getEndpoint()).whenNonNull().to(cloudWatchProperties::setEndpoint);
+ propertyMapper.from(awsRegionProvider.getRegion().id()).whenNonNull().to(cloudWatchProperties::setRegion);
+ CloudWatchAsyncClient cloudWatchAsyncClient = awsClientBuilderConfigurer
+ .configure(cloudWatchAsyncClientBuilder, cloudWatchProperties, configurer.getIfAvailable(), null)
+ .build();
+
+ CloudWatchMetricPublisher.Builder builder = CloudWatchMetricPublisher.builder();
+ builder.cloudWatchClient(cloudWatchAsyncClient);
+
+ if (awsProperties.getMetrics() != null) {
+ propertyMapper.from(awsProperties.getMetrics()::getNamespace).whenNonNull().to(builder::namespace);
+ propertyMapper.from(awsProperties.getMetrics()::getUploadFrequencyInSeconds).whenNonNull()
+ .to(v -> builder.uploadFrequency(Duration.ofSeconds(v)));
+ }
+ return builder.build();
+ }
+}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherProperties.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherProperties.java
new file mode 100644
index 000000000..9e48a4e1b
--- /dev/null
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherProperties.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2013-2022 the original author or authors.
+ *
+ * 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
+ *
+ * https://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 io.awspring.cloud.autoconfigure.core;
+
+import org.springframework.lang.Nullable;
+
+public class CloudWatchMetricsPublisherProperties {
+ @Nullable
+ private boolean enabled;
+ @Nullable
+ private String namespace;
+ @Nullable
+ private Long uploadFrequencyInSeconds;
+
+ @Nullable
+ public boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(@Nullable boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Nullable
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(@Nullable String namespace) {
+ this.namespace = namespace;
+ }
+
+ @Nullable
+ public Long getUploadFrequencyInSeconds() {
+ return uploadFrequencyInSeconds;
+ }
+
+ public void setUploadFrequencyInSeconds(@Nullable Long uploadFrequencyInSeconds) {
+ this.uploadFrequencyInSeconds = uploadFrequencyInSeconds;
+ }
+}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java
index 246a7f71b..96e214821 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfiguration.java
@@ -15,6 +15,8 @@
*/
package io.awspring.cloud.autoconfigure.dynamodb;
+import static io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer.createSpecificMetricPublisher;
+
import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
@@ -31,6 +33,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
+import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder;
@@ -55,10 +58,19 @@ public DynamoDbAutoConfiguration(DynamoDbProperties properties) {
@ConditionalOnMissingBean
@Bean
- public DynamoDbClient dynamoDbClient(AwsClientBuilderConfigurer awsClientBuilderConfigurer,
- ObjectProvider> configurer) {
- return awsClientBuilderConfigurer.configure(DynamoDbClient.builder(), properties, configurer.getIfAvailable())
- .build();
+ public DynamoDbClientBuilder dynamoDbClientBuilder(AwsClientBuilderConfigurer awsClientBuilderConfigurer,
+ ObjectProvider> configurer,
+ ObjectProvider metricPublisherObjectProvider) {
+ MetricPublisher metricPublisher = createSpecificMetricPublisher(metricPublisherObjectProvider.getIfAvailable(),
+ properties, awsClientBuilderConfigurer);
+ return awsClientBuilderConfigurer.configure(DynamoDbClient.builder(), properties, configurer.getIfAvailable(),
+ metricPublisher);
+ }
+
+ @ConditionalOnMissingBean
+ @Bean
+ public DynamoDbClient dynamoDbClient(DynamoDbClientBuilder dynamoDbClientBuilder) {
+ return dynamoDbClientBuilder.build();
}
@ConditionalOnMissingBean
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/metrics/CloudWatchExportAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/metrics/CloudWatchExportAutoConfiguration.java
index a3881c9ee..28c0aa024 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/metrics/CloudWatchExportAutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/metrics/CloudWatchExportAutoConfiguration.java
@@ -34,6 +34,7 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClientBuilder;
@@ -67,9 +68,10 @@ public CloudWatchMeterRegistry cloudWatchMeterRegistry(CloudWatchConfig config,
@ConditionalOnMissingBean
public CloudWatchAsyncClient cloudWatchAsyncClient(CloudWatchProperties properties,
AwsClientBuilderConfigurer awsClientBuilderConfigurer,
- ObjectProvider> configurer) {
- return awsClientBuilderConfigurer
- .configure(CloudWatchAsyncClient.builder(), properties, configurer.getIfAvailable()).build();
+ ObjectProvider> configurer,
+ ObjectProvider metricPublisherObjectProvider) {
+ return awsClientBuilderConfigurer.configure(CloudWatchAsyncClient.builder(), properties,
+ configurer.getIfAvailable(), metricPublisherObjectProvider.getIfAvailable()).build();
}
@Bean
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java
index c670caeda..4f8c847c3 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfiguration.java
@@ -15,6 +15,8 @@
*/
package io.awspring.cloud.autoconfigure.s3;
+import static io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer.createSpecificMetricPublisher;
+
import com.fasterxml.jackson.databind.ObjectMapper;
import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
@@ -43,6 +45,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.S3Configuration;
@@ -68,9 +71,12 @@ public S3AutoConfiguration(S3Properties properties) {
@Bean
@ConditionalOnMissingBean
S3ClientBuilder s3ClientBuilder(AwsClientBuilderConfigurer awsClientBuilderConfigurer,
- ObjectProvider> configurer) {
+ ObjectProvider> configurer,
+ ObjectProvider metricPublisherObjectProvider) {
+ MetricPublisher metricPublisher = createSpecificMetricPublisher(metricPublisherObjectProvider.getIfAvailable(),
+ properties, awsClientBuilderConfigurer);
S3ClientBuilder builder = awsClientBuilderConfigurer.configure(S3Client.builder(), this.properties,
- configurer.getIfAvailable());
+ configurer.getIfAvailable(), metricPublisher);
builder.serviceConfiguration(s3ServiceConfiguration());
return builder;
}
@@ -137,5 +143,4 @@ S3OutputStreamProvider inMemoryBufferingS3StreamProvider(S3Client s3Client,
return new InMemoryBufferingS3OutputStreamProvider(s3Client,
contentTypeResolver.orElseGet(PropertiesS3ObjectContentTypeResolver::new));
}
-
}
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfiguration.java
index 5fb865fcf..373a25acd 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfiguration.java
@@ -15,6 +15,8 @@
*/
package io.awspring.cloud.autoconfigure.ses;
+import static io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer.createSpecificMetricPublisher;
+
import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
@@ -33,6 +35,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.MailSender;
import org.springframework.mail.javamail.JavaMailSender;
+import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.services.ses.SesClient;
import software.amazon.awssdk.services.ses.SesClientBuilder;
@@ -53,10 +56,20 @@ public class SesAutoConfiguration {
@Bean
@ConditionalOnMissingBean
- public SesClient sesClient(SesProperties properties, AwsClientBuilderConfigurer awsClientBuilderConfigurer,
- ObjectProvider> configurer) {
- return awsClientBuilderConfigurer.configure(SesClient.builder(), properties, configurer.getIfAvailable())
- .build();
+ public SesClientBuilder sesClientBuilder(SesProperties properties,
+ AwsClientBuilderConfigurer awsClientBuilderConfigurer,
+ ObjectProvider> configurer,
+ ObjectProvider metricPublisherObjectProvider) {
+ MetricPublisher metricPublisher = createSpecificMetricPublisher(metricPublisherObjectProvider.getIfAvailable(),
+ properties, awsClientBuilderConfigurer);
+ return awsClientBuilderConfigurer.configure(SesClient.builder(), properties, configurer.getIfAvailable(),
+ metricPublisher);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SesClient sesClient(SesClientBuilder sesClientBuilder) {
+ return sesClientBuilder.build();
}
@Bean
diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfiguration.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfiguration.java
index 1708095a4..96a2e41a7 100644
--- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfiguration.java
+++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfiguration.java
@@ -15,6 +15,7 @@
*/
package io.awspring.cloud.autoconfigure.sns;
+import static io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer.createSpecificMetricPublisher;
import static io.awspring.cloud.sns.configuration.NotificationHandlerMethodArgumentResolverConfigurationUtils.getNotificationHandlerMethodArgumentResolver;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -38,6 +39,7 @@
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import software.amazon.awssdk.metrics.MetricPublisher;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.SnsClientBuilder;
@@ -60,10 +62,20 @@ public class SnsAutoConfiguration {
@ConditionalOnMissingBean
@Bean
- public SnsClient snsClient(SnsProperties properties, AwsClientBuilderConfigurer awsClientBuilderConfigurer,
- ObjectProvider> configurer) {
- return awsClientBuilderConfigurer.configure(SnsClient.builder(), properties, configurer.getIfAvailable())
- .build();
+ public SnsClientBuilder snsClientBuilder(SnsProperties properties,
+ AwsClientBuilderConfigurer awsClientBuilderConfigurer,
+ ObjectProvider> configurer,
+ ObjectProvider metricPublisherObjectProvider) {
+ MetricPublisher metricPublisher = createSpecificMetricPublisher(metricPublisherObjectProvider.getIfAvailable(),
+ properties, awsClientBuilderConfigurer);
+ return awsClientBuilderConfigurer.configure(SnsClient.builder(), properties, configurer.getIfAvailable(),
+ metricPublisher);
+ }
+
+ @ConditionalOnMissingBean
+ @Bean
+ public SnsClient snsClient(SnsClientBuilder snsClientBuilder) {
+ return snsClientBuilder.build();
}
@ConditionalOnMissingBean
diff --git a/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories
index d8cb47a45..7e2068df8 100644
--- a/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -3,6 +3,7 @@ io.awspring.cloud.autoconfigure.core.AwsAutoConfiguration,\
io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration,\
io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration,\
io.awspring.cloud.autoconfigure.metrics.CloudWatchExportAutoConfiguration,\
+io.awspring.cloud.autoconfigure.core.CloudWatchMetricsPublisherAutoConfiguration,\
io.awspring.cloud.autoconfigure.ses.SesAutoConfiguration,\
io.awspring.cloud.autoconfigure.s3.S3TransferManagerAutoConfiguration,\
io.awspring.cloud.autoconfigure.s3.S3AutoConfiguration,\
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLoaderIntegrationTests.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLoaderIntegrationTests.java
index 16c0e79b4..d2a7bb56a 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLoaderIntegrationTests.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/parameterstore/ParameterStoreConfigDataLoaderIntegrationTests.java
@@ -37,6 +37,7 @@
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.util.ReflectionTestUtils;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -46,6 +47,8 @@
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.internal.transform.MetricCollectionAggregator;
import software.amazon.awssdk.services.ssm.SsmClient;
import software.amazon.awssdk.services.ssm.model.GetParametersByPathRequest;
import software.amazon.awssdk.services.ssm.model.GetParametersByPathResponse;
@@ -210,6 +213,37 @@ void parameterStoreClientUsesGlobalRegion() {
}
}
+ @Test
+ void clientIsConfiguredWithConfigurerProvidedToBootstrapRegistry2() {
+ SpringApplication application = new SpringApplication(App.class);
+ application.setWebApplicationType(WebApplicationType.NONE);
+ application.addBootstrapRegistryInitializer(new AwsConfigurerClientConfiguration());
+
+ try (ConfigurableApplicationContext context = application.run(
+ "--spring.cloud.aws.parameterstore.metrics.namespace=custom",
+ "--spring.config.import=aws-parameterstore:/config/spring/",
+ "--spring.cloud.aws.parameterstore.region=" + REGION,
+ "--spring.cloud.aws.endpoint=http://non-existing-host/",
+ "--spring.cloud.aws.parameterstore.endpoint=" + localstack.getEndpointOverride(SSM).toString(),
+ "--spring.cloud.aws.credentials.access-key=noop", "--spring.cloud.aws.credentials.secret-key=noop",
+ "--spring.cloud.aws.region.static=eu-west-1",
+ "--logging.level.io.awspring.cloud.parameterstore=debug")) {
+
+ CloudWatchMetricPublisher metricPublisher = (CloudWatchMetricPublisher) context.getBean(SsmClient.class)
+ .overrideConfiguration().metricPublishers().get(0);
+ MetricCollectionAggregator metricAggregator = (MetricCollectionAggregator) ReflectionTestUtils
+ .getField(metricPublisher, "metricAggregator");
+
+ String namespace = (String) ReflectionTestUtils.getField(metricAggregator, "namespace");
+ assertThat(namespace).isEqualTo("custom");
+ }
+ }
+
+ @Test
+ void parameterStoreUsesCustomEndpointForMetricsIfDefined() {
+
+ }
+
private ConfigurableApplicationContext runApplication(SpringApplication application, String springConfigImport,
String endpointProperty) {
return application.run("--spring.config.import=" + springConfigImport,
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/AwsAutoConfigurationTests.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/AwsAutoConfigurationTests.java
new file mode 100644
index 000000000..5e41536bb
--- /dev/null
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/AwsAutoConfigurationTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2013-2022 the original author or authors.
+ *
+ * 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
+ *
+ * https://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 io.awspring.cloud.autoconfigure.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.FilteredClassLoader;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+
+class AwsAutoConfigurationTests {
+
+ private static ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(
+ AutoConfigurations.of(CredentialsProviderAutoConfiguration.class, AwsAutoConfiguration.class))
+ .withBean(CustomRegionProvider.class);
+
+ @Test
+ void doesNotCreateMetricsPublisherWhenDisabledExplicitlyAndDependencyInClasspath() {
+ contextRunner.withPropertyValues("spring.cloud.aws.metrics.enabled:false")
+ .run((context) -> assertThat(context).doesNotHaveBean(MetricPublisher.class));
+ }
+
+ @Test
+ void doesNotCreateMetricsPublisherWhenDependencyNotInClasspath() {
+ contextRunner.withClassLoader(new FilteredClassLoader(CloudWatchMetricPublisher.class))
+ .run((context) -> assertThat(context).doesNotHaveBean(MetricPublisher.class));
+ }
+
+}
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherAutoConfigurationTests.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherAutoConfigurationTests.java
new file mode 100644
index 000000000..b9627f8c0
--- /dev/null
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/CloudWatchMetricsPublisherAutoConfigurationTests.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013-2022 the original author or authors.
+ *
+ * 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
+ *
+ * https://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 io.awspring.cloud.autoconfigure.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import software.amazon.awssdk.metrics.MetricPublisher;
+
+class CloudWatchMetricsPublisherAutoConfigurationTests {
+
+ private static ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
+ .withConfiguration(AutoConfigurations.of(RegionProviderAutoConfiguration.class,
+ CredentialsProviderAutoConfiguration.class, CloudWatchMetricsPublisherAutoConfiguration.class,
+ AwsAutoConfiguration.class));
+
+ @Test
+ void createsMetricsPublisherByDefaultWhenDependencyInClasspath() {
+ contextRunner.run((context) -> assertThat(context).hasSingleBean(MetricPublisher.class));
+ }
+
+ @Test
+ void createsMetricsPublisherWhenSpecifiedExplicitlyAndDependencyInClasspath() {
+ contextRunner.withPropertyValues("spring.cloud.aws.metrics.enabled:true")
+ .run((context) -> assertThat(context).hasSingleBean(MetricPublisher.class));
+ }
+
+}
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/CustomRegionProvider.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/CustomRegionProvider.java
new file mode 100644
index 000000000..1523a9c57
--- /dev/null
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/CustomRegionProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2013-2022 the original author or authors.
+ *
+ * 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
+ *
+ * https://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 io.awspring.cloud.autoconfigure.core;
+
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.regions.providers.AwsRegionProvider;
+
+class CustomRegionProvider implements AwsRegionProvider {
+
+ @Override
+ public Region getRegion() {
+ return null;
+ }
+
+}
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/RegionProviderAutoConfigurationTests.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/RegionProviderAutoConfigurationTests.java
index 4e3056095..f0e722e0a 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/RegionProviderAutoConfigurationTests.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/core/RegionProviderAutoConfigurationTests.java
@@ -143,13 +143,4 @@ public AwsRegionProvider customRegionProvider() {
}
- static class CustomRegionProvider implements AwsRegionProvider {
-
- @Override
- public Region getRegion() {
- return null;
- }
-
- }
-
}
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java
index ef41420e1..93145e424 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/dynamodb/DynamoDbAutoConfigurationTest.java
@@ -20,6 +20,7 @@
import io.awspring.cloud.autoconfigure.ConfiguredAwsClient;
import io.awspring.cloud.autoconfigure.core.AwsAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
+import io.awspring.cloud.autoconfigure.core.CloudWatchMetricsPublisherAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import io.awspring.cloud.dynamodb.DynamoDbTableNameResolver;
@@ -29,15 +30,20 @@
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
+import org.springframework.test.util.ReflectionTestUtils;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.internal.transform.MetricCollectionAggregator;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder;
@@ -50,8 +56,8 @@ class DynamoDbAutoConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
.withConfiguration(AutoConfigurations.of(RegionProviderAutoConfiguration.class,
- CredentialsProviderAutoConfiguration.class, DynamoDbAutoConfiguration.class,
- AwsAutoConfiguration.class));
+ CredentialsProviderAutoConfiguration.class, CloudWatchMetricsPublisherAutoConfiguration.class,
+ DynamoDbAutoConfiguration.class, AwsAutoConfiguration.class));
@Test
void dynamoDBAutoConfigurationIsDisabled() {
@@ -105,6 +111,51 @@ void customTableResolverResolverCanBeConfigured() {
});
}
+ @Test
+ void usesSpecificMetricsClientPropertiesIfSpecified() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.dynamodb.metrics.enabled:true",
+ "spring.cloud.aws.dynamodb.metrics.namespace:custom").run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(DynamoDbClientBuilder.class);
+ assertThat(context.getBean(DynamoDbClientBuilder.class).overrideConfiguration().metricPublishers()
+ .size()).isEqualTo(1);
+ CloudWatchMetricPublisher metricPublisher = (CloudWatchMetricPublisher) context
+ .getBean(DynamoDbClientBuilder.class).overrideConfiguration().metricPublishers().get(0);
+ MetricCollectionAggregator metricAggregator = (MetricCollectionAggregator) ReflectionTestUtils
+ .getField(metricPublisher, "metricAggregator");
+ String namespace = (String) ReflectionTestUtils.getField(metricAggregator, "namespace");
+ assertThat(namespace).isEqualTo("custom");
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsClientIfDisabledForclient() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.dynamodb.metrics.enabled:false").run(context -> {
+ assertThat(context.getBean(DynamoDbClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
+ @Test
+ void usesMetricsPublisherIfAvailable() {
+ this.contextRunner.run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(DynamoDbClientBuilder.class);
+ assertThat(context.getBean(DynamoDbClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsPublisherIfNotAvailable() {
+ this.contextRunner.withClassLoader(new FilteredClassLoader(CloudWatchMetricPublisher.class)).run(context -> {
+ assertThat(context).doesNotHaveBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(DynamoDbClientBuilder.class);
+ assertThat(context.getBean(DynamoDbClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
@Test
void customDynamoDbClientConfigurer() {
this.contextRunner.withUserConfiguration(DynamoDbAutoConfigurationTest.CustomAwsClientConfig.class)
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfigurationTests.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfigurationTests.java
index 985385b47..3b0ba79b3 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfigurationTests.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/s3/S3AutoConfigurationTests.java
@@ -22,6 +22,7 @@
import io.awspring.cloud.autoconfigure.ConfiguredAwsClient;
import io.awspring.cloud.autoconfigure.core.AwsAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
+import io.awspring.cloud.autoconfigure.core.CloudWatchMetricsPublisherAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.s3.properties.S3Properties;
@@ -51,6 +52,9 @@
import software.amazon.awssdk.core.client.config.SdkClientOption;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.internal.transform.MetricCollectionAggregator;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
@@ -64,7 +68,8 @@ class S3AutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
.withConfiguration(AutoConfigurations.of(AwsAutoConfiguration.class, RegionProviderAutoConfiguration.class,
- CredentialsProviderAutoConfiguration.class, S3AutoConfiguration.class));
+ CloudWatchMetricsPublisherAutoConfiguration.class, CredentialsProviderAutoConfiguration.class,
+ S3AutoConfiguration.class));
@Test
void createsS3ClientBean() {
@@ -88,6 +93,51 @@ void s3AutoConfigurationIsDisabled() {
});
}
+ @Test
+ void usesMetricsPublisherIfAvailable() {
+ this.contextRunner.run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(S3ClientBuilder.class);
+ assertThat(context.getBean(S3ClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ });
+ }
+
+ @Test
+ void usesSpecificMetricsClientPropertiesIfSpecified() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.s3.metrics.enabled:true",
+ "spring.cloud.aws.s3.metrics.namespace:custom").run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(S3ClientBuilder.class);
+ assertThat(context.getBean(S3ClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ CloudWatchMetricPublisher metricPublisher = (CloudWatchMetricPublisher) context
+ .getBean(S3ClientBuilder.class).overrideConfiguration().metricPublishers().get(0);
+ MetricCollectionAggregator metricAggregator = (MetricCollectionAggregator) ReflectionTestUtils
+ .getField(metricPublisher, "metricAggregator");
+ String namespace = (String) ReflectionTestUtils.getField(metricAggregator, "namespace");
+ assertThat(namespace).isEqualTo("custom");
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsClientIfDisabledForclient() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.s3.metrics.enabled:false").run(context -> {
+ assertThat(context.getBean(S3ClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsPublisherIfNotAvailable() {
+ this.contextRunner.withClassLoader(new FilteredClassLoader(CloudWatchMetricPublisher.class)).run(context -> {
+ assertThat(context).doesNotHaveBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(S3ClientBuilder.class);
+ assertThat(context.getBean(S3ClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
@Test
void autoconfigurationIsNotTriggeredWhenS3ModuleIsNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader(S3OutputStreamProvider.class)).run(context -> {
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfigurationTest.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfigurationTest.java
index a5b1414fb..a0f91b4ae 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfigurationTest.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfigurationTest.java
@@ -20,6 +20,7 @@
import io.awspring.cloud.autoconfigure.ConfiguredAwsClient;
import io.awspring.cloud.autoconfigure.core.AwsAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
+import io.awspring.cloud.autoconfigure.core.CloudWatchMetricsPublisherAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import java.net.URI;
@@ -32,9 +33,13 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.MailSender;
import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.test.util.ReflectionTestUtils;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.internal.transform.MetricCollectionAggregator;
import software.amazon.awssdk.services.ses.SesClient;
import software.amazon.awssdk.services.ses.SesClientBuilder;
@@ -50,7 +55,8 @@ class SesAutoConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
.withConfiguration(AutoConfigurations.of(AwsAutoConfiguration.class, RegionProviderAutoConfiguration.class,
- CredentialsProviderAutoConfiguration.class, SesAutoConfiguration.class));
+ CloudWatchMetricsPublisherAutoConfiguration.class, CredentialsProviderAutoConfiguration.class,
+ SesAutoConfiguration.class));
@Test
void mailSenderWithJavaMail() {
@@ -86,6 +92,52 @@ void sesAutoConfigurationIsDisabled() {
});
}
+ @Test
+ void usesSpecificMetricsClientPropertiesIfSpecified() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.ses.metrics.enabled:true",
+ "spring.cloud.aws.ses.metrics.namespace:custom").run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(SesClientBuilder.class);
+ assertThat(
+ context.getBean(SesClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ CloudWatchMetricPublisher metricPublisher = (CloudWatchMetricPublisher) context
+ .getBean(SesClientBuilder.class).overrideConfiguration().metricPublishers().get(0);
+ MetricCollectionAggregator metricAggregator = (MetricCollectionAggregator) ReflectionTestUtils
+ .getField(metricPublisher, "metricAggregator");
+ String namespace = (String) ReflectionTestUtils.getField(metricAggregator, "namespace");
+ assertThat(namespace).isEqualTo("custom");
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsClientIfDisabledForclient() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.ses.metrics.enabled:false").run(context -> {
+ assertThat(context.getBean(SesClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
+ @Test
+ void usesMetricsPublisherIfAvailable() {
+ this.contextRunner.run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(SesClientBuilder.class);
+ assertThat(context.getBean(SesClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsPublisherIfNotAvailable() {
+ this.contextRunner.withClassLoader(new FilteredClassLoader(CloudWatchMetricPublisher.class)).run(context -> {
+ assertThat(context).doesNotHaveBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(SesClientBuilder.class);
+ assertThat(context.getBean(SesClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
@Test
void withCustomEndpoint() {
this.contextRunner.withPropertyValues("spring.cloud.aws.ses.endpoint:http://localhost:8090").run(context -> {
diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfigurationTest.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfigurationTest.java
index bb43960b0..edcf29cca 100644
--- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfigurationTest.java
+++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/sns/SnsAutoConfigurationTest.java
@@ -20,6 +20,7 @@
import io.awspring.cloud.autoconfigure.ConfiguredAwsClient;
import io.awspring.cloud.autoconfigure.core.AwsAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
+import io.awspring.cloud.autoconfigure.core.CloudWatchMetricsPublisherAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import io.awspring.cloud.sns.core.SnsTemplate;
@@ -41,6 +42,9 @@
import software.amazon.awssdk.core.client.config.SdkClientOption;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
+import software.amazon.awssdk.metrics.MetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
+import software.amazon.awssdk.metrics.publishers.cloudwatch.internal.transform.MetricCollectionAggregator;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.SnsClientBuilder;
@@ -55,7 +59,7 @@ class SnsAutoConfigurationTest {
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
.withConfiguration(AutoConfigurations.of(RegionProviderAutoConfiguration.class,
CredentialsProviderAutoConfiguration.class, SnsAutoConfiguration.class,
- AwsAutoConfiguration.class));
+ CloudWatchMetricsPublisherAutoConfiguration.class, AwsAutoConfiguration.class));
@Test
void snsAutoConfigurationIsDisabled() {
@@ -106,6 +110,52 @@ void customSnsClientConfigurer() {
});
}
+ @Test
+ void usesSpecificMetricsClientPropertiesIfSpecified() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.sns.metrics.enabled:true",
+ "spring.cloud.aws.sns.metrics.namespace:custom").run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(SnsClientBuilder.class);
+ assertThat(
+ context.getBean(SnsClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ CloudWatchMetricPublisher metricPublisher = (CloudWatchMetricPublisher) context
+ .getBean(SnsClientBuilder.class).overrideConfiguration().metricPublishers().get(0);
+ MetricCollectionAggregator metricAggregator = (MetricCollectionAggregator) ReflectionTestUtils
+ .getField(metricPublisher, "metricAggregator");
+ String namespace = (String) ReflectionTestUtils.getField(metricAggregator, "namespace");
+ assertThat(namespace).isEqualTo("custom");
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsClientIfDisabledForclient() {
+ this.contextRunner.withPropertyValues("spring.cloud.aws.sns.metrics.enabled:false").run(context -> {
+ assertThat(context.getBean(SnsClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
+ @Test
+ void usesMetricsPublisherIfAvailable() {
+ this.contextRunner.run(context -> {
+ assertThat(context).hasSingleBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(SnsClientBuilder.class);
+ assertThat(context.getBean(SnsClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(1);
+ });
+ }
+
+ @Test
+ void doesNotUseMetricsPublisherIfNotAvailable() {
+ this.contextRunner.withClassLoader(new FilteredClassLoader(CloudWatchMetricPublisher.class)).run(context -> {
+ assertThat(context).doesNotHaveBean(MetricPublisher.class);
+ assertThat(context).hasSingleBean(SnsClientBuilder.class);
+ assertThat(context.getBean(SnsClientBuilder.class).overrideConfiguration().metricPublishers().size())
+ .isEqualTo(0);
+ });
+ }
+
@Test
void doesNotConfigureArgumentResolversWhenSpringWebNotOnTheClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader(WebMvcConfigurer.class)).run(context -> {