From 3e01bc1174329a43d825ad5bf6ed3bc2f17e6835 Mon Sep 17 00:00:00 2001 From: Chris Eager Date: Thu, 5 Aug 2021 17:21:48 -0500 Subject: [PATCH] Add metric for content-length header distribution --- .../textsecuregcm/WhisperServerService.java | 7 +++- .../filters/ContentLengthFilter.java | 37 +++++++++++++++++++ .../filters/ContentLengthFilterTest.java | 32 ++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilter.java create mode 100644 service/src/test/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilterTest.java diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index d0f9ecd6d..c521fe308 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -94,6 +94,7 @@ import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager; import org.whispersystems.textsecuregcm.currency.FixerClient; import org.whispersystems.textsecuregcm.currency.FtxClient; import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager; +import org.whispersystems.textsecuregcm.filters.ContentLengthFilter; import org.whispersystems.textsecuregcm.filters.RemoteDeprecationFilter; import org.whispersystems.textsecuregcm.filters.TimestampResponseFilter; import org.whispersystems.textsecuregcm.limits.PreKeyRateLimiter; @@ -545,6 +546,7 @@ public class WhisperServerService extends Application(ImmutableMap.of(Account.class, accountAuthFilter, @@ -556,7 +558,10 @@ public class WhisperServerService extends Application webSocketEnvironment = new WebSocketEnvironment<>(environment, config.getWebSocketConfiguration(), 90000); webSocketEnvironment.setAuthenticator(new WebSocketAccountAuthenticator(accountAuthenticator)); - webSocketEnvironment.setConnectListener(new AuthenticatedConnectListener(receiptSender, messagesManager, messageSender, apnFallbackManager, clientPresenceManager, retrySchedulingExecutor)); + webSocketEnvironment.setConnectListener( + new AuthenticatedConnectListener(receiptSender, messagesManager, messageSender, apnFallbackManager, + clientPresenceManager, retrySchedulingExecutor)); + webSocketEnvironment.jersey().register(new ContentLengthFilter(TrafficSource.WEBSOCKET)); webSocketEnvironment.jersey().register(MultiRecipientMessageProvider.class); webSocketEnvironment.jersey().register(new MetricsApplicationEventListener(TrafficSource.WEBSOCKET)); webSocketEnvironment.jersey().register(new KeepAliveController(clientPresenceManager)); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilter.java b/service/src/main/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilter.java new file mode 100644 index 000000000..36fbc9023 --- /dev/null +++ b/service/src/main/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2021 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.textsecuregcm.filters; + +import static com.codahale.metrics.MetricRegistry.name; + +import io.micrometer.core.instrument.Metrics; +import java.io.IOException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.whispersystems.textsecuregcm.metrics.TrafficSource; + +public class ContentLengthFilter implements ContainerRequestFilter { + + private static final String CONTENT_LENGTH_DISTRIBUTION_NAME = name(ContentLengthFilter.class, "contentLength"); + + private static final Logger logger = LoggerFactory.getLogger(ContentLengthFilter.class); + private final TrafficSource trafficSource; + + public ContentLengthFilter(final TrafficSource trafficeSource) { + this.trafficSource = trafficeSource; + } + + @Override + public void filter(final ContainerRequestContext requestContext) throws IOException { + try { + Metrics.summary(CONTENT_LENGTH_DISTRIBUTION_NAME, "trafficSource", trafficSource.name().toLowerCase()).record(requestContext.getLength()); + } catch (final Exception e) { + logger.warn("Error recording content length", e); + } + } +} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilterTest.java new file mode 100644 index 000000000..7a9b2ca09 --- /dev/null +++ b/service/src/test/java/org/whispersystems/textsecuregcm/filters/ContentLengthFilterTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2021 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.textsecuregcm.filters; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import javax.ws.rs.container.ContainerRequestContext; +import org.junit.jupiter.api.Test; +import org.whispersystems.textsecuregcm.metrics.TrafficSource; + +class ContentLengthFilterTest { + + @Test + void testFilter() throws Exception { + + final ContentLengthFilter contentLengthFilter = new ContentLengthFilter(TrafficSource.WEBSOCKET); + + final ContainerRequestContext requestContext = mock(ContainerRequestContext.class); + + when(requestContext.getLength()).thenReturn(-1); + when(requestContext.getLength()).thenReturn(Integer.MAX_VALUE); + when(requestContext.getLength()).thenThrow(RuntimeException.class); + + contentLengthFilter.filter(requestContext); + contentLengthFilter.filter(requestContext); + contentLengthFilter.filter(requestContext); + } +}