diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/metrics/OpenWebSocketCounter.java b/service/src/main/java/org/whispersystems/textsecuregcm/metrics/OpenWebSocketCounter.java index 0273857a6..b249f5f92 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/metrics/OpenWebSocketCounter.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/metrics/OpenWebSocketCounter.java @@ -18,26 +18,35 @@ public class OpenWebSocketCounter { private static final String WEBSOCKET_CLOSED_COUNTER_NAME = name(OpenWebSocketCounter.class, "websocketClosed"); + private final String newConnectionCounterName; + private final String durationTimerName; + + private final Tags tags; + private final Map openWebsocketsByClientPlatform; private final AtomicInteger openWebsocketsFromUnknownPlatforms; - private final Map durationTimersByClientPlatform; - private final Timer durationTimerForUnknownPlatforms; + public OpenWebSocketCounter(final String openWebSocketGaugeName, + final String newConnectionCounterName, + final String durationTimerName) { - public OpenWebSocketCounter(final String openWebSocketGaugeName, final String durationTimerName) { - this(openWebSocketGaugeName, durationTimerName, Tags.empty()); + this(openWebSocketGaugeName, durationTimerName, newConnectionCounterName, Tags.empty()); } - public OpenWebSocketCounter(final String openWebSocketGaugeName, final String durationTimerName, final Tags tags) { + public OpenWebSocketCounter(final String openWebSocketGaugeName, + final String newConnectionCounterName, + final String durationTimerName, + final Tags tags) { + + this.newConnectionCounterName = newConnectionCounterName; + this.durationTimerName = durationTimerName; + + this.tags = tags; + openWebsocketsByClientPlatform = EnumMapUtil.toEnumMap(ClientPlatform.class, clientPlatform -> buildGauge(openWebSocketGaugeName, clientPlatform.name().toLowerCase(), tags)); openWebsocketsFromUnknownPlatforms = buildGauge(openWebSocketGaugeName, "unknown", tags); - - durationTimersByClientPlatform = EnumMapUtil.toEnumMap(ClientPlatform.class, - clientPlatform -> buildTimer(durationTimerName, clientPlatform.name().toLowerCase(), tags)); - - durationTimerForUnknownPlatforms = buildTimer(durationTimerName, "unknown", tags); } private static AtomicInteger buildGauge(final String gaugeName, final String clientPlatformName, final Tags tags) { @@ -46,47 +55,43 @@ public class OpenWebSocketCounter { new AtomicInteger(0)); } - private static Timer buildTimer(final String timerName, final String clientPlatformName, final Tags tags) { - return Timer.builder(timerName) - .publishPercentileHistogram(true) - .tags(tags.and(Tag.of(UserAgentTagUtil.PLATFORM_TAG, clientPlatformName))) - .register(Metrics.globalRegistry); - } - public void countOpenWebSocket(final WebSocketSessionContext context) { final Timer.Sample sample = Timer.start(); // We have to jump through some hoops here to have something "effectively final" for the close listener, but // assignable from a `catch` block. final AtomicInteger openWebSocketCounter; - final Timer durationTimer; { AtomicInteger calculatedOpenWebSocketCounter; - Timer calculatedDurationTimer; try { final ClientPlatform clientPlatform = UserAgentUtil.parseUserAgentString(context.getClient().getUserAgent()).platform(); calculatedOpenWebSocketCounter = openWebsocketsByClientPlatform.get(clientPlatform); - calculatedDurationTimer = durationTimersByClientPlatform.get(clientPlatform); } catch (final UnrecognizedUserAgentException e) { calculatedOpenWebSocketCounter = openWebsocketsFromUnknownPlatforms; - calculatedDurationTimer = durationTimerForUnknownPlatforms; } openWebSocketCounter = calculatedOpenWebSocketCounter; - durationTimer = calculatedDurationTimer; } openWebSocketCounter.incrementAndGet(); + final Tags tagsWithClientPlatform = tags.and(UserAgentTagUtil.getPlatformTag(context.getClient().getUserAgent())); + + Metrics.counter(newConnectionCounterName, tagsWithClientPlatform).increment(); + context.addWebsocketClosedListener((context1, statusCode, reason) -> { - sample.stop(durationTimer); + sample.stop(Timer.builder(durationTimerName) + .publishPercentileHistogram(true) + .tags(tagsWithClientPlatform) + .register(Metrics.globalRegistry)); + openWebSocketCounter.decrementAndGet(); - Metrics.counter(WEBSOCKET_CLOSED_COUNTER_NAME, "status", String.valueOf(statusCode)) + Metrics.counter(WEBSOCKET_CLOSED_COUNTER_NAME, tagsWithClientPlatform.and("status", String.valueOf(statusCode))) .increment(); }); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java index 43ced48c7..e8f79adaa 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java @@ -33,6 +33,7 @@ import reactor.core.scheduler.Scheduler; public class AuthenticatedConnectListener implements WebSocketConnectListener { private static final String OPEN_WEBSOCKET_GAUGE_NAME = name(WebSocketConnection.class, "openWebsockets"); + private static final String NEW_CONNECTION_COUNTER_NAME = name(AuthenticatedConnectListener.class, "newConnections"); private static final String CONNECTED_DURATION_TIMER_NAME = name(AuthenticatedConnectListener.class, "connectedDuration"); @@ -84,10 +85,10 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener { this.experimentEnrollmentManager = experimentEnrollmentManager; openAuthenticatedWebSocketCounter = - new OpenWebSocketCounter(OPEN_WEBSOCKET_GAUGE_NAME, CONNECTED_DURATION_TIMER_NAME, Tags.of(AUTHENTICATED_TAG_NAME, "true")); + new OpenWebSocketCounter(OPEN_WEBSOCKET_GAUGE_NAME, NEW_CONNECTION_COUNTER_NAME, CONNECTED_DURATION_TIMER_NAME, Tags.of(AUTHENTICATED_TAG_NAME, "true")); openUnauthenticatedWebSocketCounter = - new OpenWebSocketCounter(OPEN_WEBSOCKET_GAUGE_NAME, CONNECTED_DURATION_TIMER_NAME, Tags.of(AUTHENTICATED_TAG_NAME, "false")); + new OpenWebSocketCounter(OPEN_WEBSOCKET_GAUGE_NAME, NEW_CONNECTION_COUNTER_NAME, CONNECTED_DURATION_TIMER_NAME, Tags.of(AUTHENTICATED_TAG_NAME, "false")); } @Override diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/ProvisioningConnectListener.java b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/ProvisioningConnectListener.java index bed75259d..8eb6287b0 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/ProvisioningConnectListener.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/ProvisioningConnectListener.java @@ -54,6 +54,7 @@ public class ProvisioningConnectListener implements WebSocketConnectListener { this.timeoutExecutor = timeoutExecutor; this.timeout = timeout; this.openWebSocketCounter = new OpenWebSocketCounter(MetricsUtil.name(getClass(), "openWebsockets"), + MetricsUtil.name(getClass(), "newConnections"), MetricsUtil.name(getClass(), "sessionDuration")); }