diff --git a/integration-tests/src/main/java/org/signal/integration/IntegrationTools.java b/integration-tests/src/main/java/org/signal/integration/IntegrationTools.java index 160022ca3..d8ce4da15 100644 --- a/integration-tests/src/main/java/org/signal/integration/IntegrationTools.java +++ b/integration-tests/src/main/java/org/signal/integration/IntegrationTools.java @@ -10,6 +10,7 @@ import java.time.Duration; import java.util.Optional; import java.util.concurrent.CompletableFuture; import org.signal.integration.config.Config; +import org.whispersystems.textsecuregcm.metrics.NoopAwsSdkMetricPublisher; import org.whispersystems.textsecuregcm.registration.VerificationSession; import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswords; import org.whispersystems.textsecuregcm.storage.RegistrationRecoveryPasswordsManager; @@ -30,9 +31,11 @@ public class IntegrationTools { public static IntegrationTools create(final Config config) { final AwsCredentialsProvider credentialsProvider = DefaultCredentialsProvider.builder().build(); - final DynamoDbAsyncClient dynamoDbAsyncClient = config.dynamoDbClient().buildAsyncClient(credentialsProvider); + final DynamoDbAsyncClient dynamoDbAsyncClient = + config.dynamoDbClient().buildAsyncClient(credentialsProvider, new NoopAwsSdkMetricPublisher()); - final DynamoDbClient dynamoDbClient = config.dynamoDbClient().buildSyncClient(credentialsProvider); + final DynamoDbClient dynamoDbClient = + config.dynamoDbClient().buildSyncClient(credentialsProvider, new NoopAwsSdkMetricPublisher()); final RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords( config.dynamoDbTables().registrationRecovery(), Duration.ofDays(1), dynamoDbClient, dynamoDbAsyncClient); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 8c5d1a419..d49ad1391 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -186,6 +186,7 @@ import org.whispersystems.textsecuregcm.metrics.MessageMetrics; import org.whispersystems.textsecuregcm.metrics.MetricsApplicationEventListener; import org.whispersystems.textsecuregcm.metrics.MetricsHttpChannelListener; import org.whispersystems.textsecuregcm.metrics.MetricsUtil; +import org.whispersystems.textsecuregcm.metrics.MicrometerAwsSdkMetricPublisher; import org.whispersystems.textsecuregcm.metrics.ReportedMessageMetricsListener; import org.whispersystems.textsecuregcm.metrics.TrafficSource; import org.whispersystems.textsecuregcm.providers.MultiRecipientMessageProvider; @@ -393,10 +394,15 @@ public class WhisperServerService extends Application messageDeletionQueue = new LinkedBlockingQueue<>(); Metrics.gaugeCollectionSize(name(getClass(), "messageDeletionQueueSize"), Collections.emptyList(), diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientConfiguration.java index 7cff3be18..a1405c271 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientConfiguration.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientConfiguration.java @@ -14,6 +14,7 @@ import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.http.crt.AwsCrtHttpClient; import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; @@ -39,13 +40,14 @@ public record DynamoDbClientConfiguration(@NotBlank String region, } @Override - public DynamoDbClient buildSyncClient(final AwsCredentialsProvider credentialsProvider) { + public DynamoDbClient buildSyncClient(final AwsCredentialsProvider credentialsProvider, final MetricPublisher metricPublisher) { return DynamoDbClient.builder() .region(Region.of(region())) .credentialsProvider(credentialsProvider) .overrideConfiguration(ClientOverrideConfiguration.builder() .apiCallTimeout(clientExecutionTimeout()) .apiCallAttemptTimeout(clientRequestTimeout()) + .addMetricPublisher(metricPublisher) .build()) .httpClientBuilder(AwsCrtHttpClient.builder() .maxConcurrency(maxConnections())) @@ -53,13 +55,14 @@ public record DynamoDbClientConfiguration(@NotBlank String region, } @Override - public DynamoDbAsyncClient buildAsyncClient(final AwsCredentialsProvider credentialsProvider) { + public DynamoDbAsyncClient buildAsyncClient(final AwsCredentialsProvider credentialsProvider, final MetricPublisher metricPublisher) { return DynamoDbAsyncClient.builder() .region(Region.of(region())) .credentialsProvider(credentialsProvider) .overrideConfiguration(ClientOverrideConfiguration.builder() .apiCallTimeout(clientExecutionTimeout()) .apiCallAttemptTimeout(clientRequestTimeout()) + .addMetricPublisher(metricPublisher) .build()) .httpClientBuilder(NettyNioAsyncHttpClient.builder() .maxConcurrency(maxConnections())) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientFactory.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientFactory.java index c2f7b75da..70c59d22b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientFactory.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/DynamoDbClientFactory.java @@ -8,13 +8,14 @@ package org.whispersystems.textsecuregcm.configuration; import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.dropwizard.jackson.Discoverable; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = DynamoDbClientConfiguration.class) public interface DynamoDbClientFactory extends Discoverable { - DynamoDbClient buildSyncClient(AwsCredentialsProvider awsCredentialsProvider); + DynamoDbClient buildSyncClient(AwsCredentialsProvider awsCredentialsProvider, MetricPublisher metricPublisher); - DynamoDbAsyncClient buildAsyncClient(AwsCredentialsProvider awsCredentialsProvider); + DynamoDbAsyncClient buildAsyncClient(AwsCredentialsProvider awsCredentialsProvider, MetricPublisher metricPublisher); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/metrics/NoopAwsSdkMetricPublisher.java b/service/src/main/java/org/whispersystems/textsecuregcm/metrics/NoopAwsSdkMetricPublisher.java new file mode 100644 index 000000000..d58c3165b --- /dev/null +++ b/service/src/main/java/org/whispersystems/textsecuregcm/metrics/NoopAwsSdkMetricPublisher.java @@ -0,0 +1,15 @@ +package org.whispersystems.textsecuregcm.metrics; + +import software.amazon.awssdk.metrics.MetricCollection; +import software.amazon.awssdk.metrics.MetricPublisher; + +public class NoopAwsSdkMetricPublisher implements MetricPublisher { + + @Override + public void publish(final MetricCollection metricCollection) { + } + + @Override + public void close() { + } +} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/workers/CommandDependencies.java b/service/src/main/java/org/whispersystems/textsecuregcm/workers/CommandDependencies.java index f7dfcba61..f17420bc1 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/workers/CommandDependencies.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/workers/CommandDependencies.java @@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.workers; import static com.codahale.metrics.MetricRegistry.name; +import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.DeserializationFeature; import io.dropwizard.core.setup.Environment; import io.lettuce.core.resource.ClientResources; @@ -32,6 +33,8 @@ import org.whispersystems.textsecuregcm.controllers.SecureStorageController; import org.whispersystems.textsecuregcm.controllers.SecureValueRecovery2Controller; import org.whispersystems.textsecuregcm.experiment.PushNotificationExperimentSamples; import org.whispersystems.textsecuregcm.limits.RateLimiters; +import org.whispersystems.textsecuregcm.metrics.MicrometerAwsSdkMetricPublisher; +import org.whispersystems.textsecuregcm.metrics.NoopAwsSdkMetricPublisher; import org.whispersystems.textsecuregcm.push.APNSender; import org.whispersystems.textsecuregcm.push.PushNotificationScheduler; import org.whispersystems.textsecuregcm.push.ClientPresenceManager; @@ -148,11 +151,14 @@ record CommandDependencies( ExternalServiceCredentialsGenerator secureValueRecoveryCredentialsGenerator = SecureValueRecovery2Controller.credentialsGenerator( configuration.getSvr2Configuration()); + final ExecutorService awsSdkMetricsExecutor = environment.lifecycle() + .virtualExecutorService(MetricRegistry.name(CommandDependencies.class, "awsSdkMetrics-%d")); + DynamoDbAsyncClient dynamoDbAsyncClient = configuration.getDynamoDbClientConfiguration() - .buildAsyncClient(awsCredentialsProvider); + .buildAsyncClient(awsCredentialsProvider, new MicrometerAwsSdkMetricPublisher(awsSdkMetricsExecutor, "dynamoDbAsyncCommand")); DynamoDbClient dynamoDbClient = configuration.getDynamoDbClientConfiguration() - .buildSyncClient(awsCredentialsProvider); + .buildSyncClient(awsCredentialsProvider, new MicrometerAwsSdkMetricPublisher(awsSdkMetricsExecutor, "dynamoDbSyncCommand")); RegistrationRecoveryPasswords registrationRecoveryPasswords = new RegistrationRecoveryPasswords( configuration.getDynamoDbTables().getRegistrationRecovery().getTableName(), diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/WhisperServerServiceTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/WhisperServerServiceTest.java index e816a3261..356bf17e1 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/WhisperServerServiceTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/WhisperServerServiceTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.whispersystems.textsecuregcm.metrics.NoopAwsSdkMetricPublisher; import org.whispersystems.textsecuregcm.storage.DynamoDbExtension; import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema; import org.whispersystems.textsecuregcm.tests.util.TestWebsocketListener; @@ -110,7 +111,7 @@ class WhisperServerServiceTest { .build(); try (DynamoDbClient dynamoDbClient = EXTENSION.getConfiguration().getDynamoDbClientConfiguration() - .buildSyncClient(awsCredentialsProvider)) { + .buildSyncClient(awsCredentialsProvider, new NoopAwsSdkMetricPublisher())) { final DynamoDbExtension.TableSchema numbers = DynamoDbExtensionSchema.Tables.NUMBERS; final AttributeValue numberAV = AttributeValues.s("+12125550001"); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/configuration/LocalDynamoDbFactory.java b/service/src/test/java/org/whispersystems/textsecuregcm/configuration/LocalDynamoDbFactory.java index 3cfeae1dd..f87f70dae 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/configuration/LocalDynamoDbFactory.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/configuration/LocalDynamoDbFactory.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonTypeName; import org.whispersystems.textsecuregcm.storage.DynamoDbExtension; import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.metrics.MetricPublisher; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; @@ -29,12 +30,12 @@ public class LocalDynamoDbFactory implements DynamoDbClientFactory { } @Override - public DynamoDbClient buildSyncClient(final AwsCredentialsProvider awsCredentialsProvider) { + public DynamoDbClient buildSyncClient(final AwsCredentialsProvider awsCredentialsProvider, final MetricPublisher metricPublisher) { return EXTENSION.getDynamoDbClient(); } @Override - public DynamoDbAsyncClient buildAsyncClient(final AwsCredentialsProvider awsCredentialsProvider) { + public DynamoDbAsyncClient buildAsyncClient(final AwsCredentialsProvider awsCredentialsProvider, final MetricPublisher metricPublisher) { return EXTENSION.getDynamoDbAsyncClient(); } }