diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69677948..041042c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,14 +5,19 @@ on: [push] jobs: build: runs-on: ubuntu-latest + container: ubuntu:22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Set up JDK 17 - uses: actions/setup-java@3bc31aaf88e8fc94dc1e632d48af61be5ca8721c + uses: actions/setup-java@de1bb2b0c5634f0fc4438d7aa9944e68f9bf86cc # v3.6.0 with: distribution: 'temurin' java-version: 17 cache: 'maven' + env: + # work around an issue with actions/runner setting an incorrect HOME in containers, which breaks maven caching + # https://github.com/actions/setup-java/issues/356 + HOME: /root - name: Build with Maven - run: mvn -e -B verify + run: ./mvnw -e -B verify diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/metrics/NstatCounters.java b/service/src/main/java/org/whispersystems/textsecuregcm/metrics/NstatCounters.java deleted file mode 100644 index aa5e56a5..00000000 --- a/service/src/main/java/org/whispersystems/textsecuregcm/metrics/NstatCounters.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2021 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.metrics; - -import static com.codahale.metrics.MetricRegistry.name; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.annotations.VisibleForTesting; -import io.micrometer.core.instrument.Metrics; -import java.io.IOException; -import java.time.Duration; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NstatCounters { - - private final Map networkStatistics = new ConcurrentHashMap<>(); - - private static final String[] NSTAT_COMMAND_LINE = new String[] { "nstat", "--zero", "--json", "--noupdate", "--ignore" }; - private static final String[] EXCLUDE_METRIC_NAME_PREFIXES = new String[] { "Icmp", "Udp", "Ip6" }; - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - private static final Logger log = LoggerFactory.getLogger(NstatCounters.class); - - @VisibleForTesting - static class NetworkStatistics { - private final Map kernelStatistics; - - @JsonCreator - private NetworkStatistics(@JsonProperty("kernel") final Map kernelStatistics) { - this.kernelStatistics = kernelStatistics; - } - - public Map getKernelStatistics() { - return kernelStatistics; - } - } - - public void registerMetrics(final ScheduledExecutorService refreshService, final Duration refreshInterval) { - refreshNetworkStatistics(); - - networkStatistics.keySet().stream() - .filter(NstatCounters::shouldIncludeMetric) - .forEach(metricName -> Metrics.globalRegistry.more().counter(name(getClass(), "kernel", metricName), - Collections.emptyList(), networkStatistics, statistics -> statistics.get(metricName))); - - refreshService.scheduleAtFixedRate(this::refreshNetworkStatistics, - refreshInterval.toMillis(), refreshInterval.toMillis(), TimeUnit.MILLISECONDS); - } - - private void refreshNetworkStatistics() { - try { - networkStatistics.putAll(loadNetworkStatistics().getKernelStatistics()); - } catch (final InterruptedException | IOException e) { - log.warn("Failed to refresh network statistics", e); - } - } - - @VisibleForTesting - static boolean shouldIncludeMetric(final String metricName) { - for (final String prefix : EXCLUDE_METRIC_NAME_PREFIXES) { - if (metricName.startsWith(prefix)) { - return false; - } - } - - return true; - } - - @VisibleForTesting - static NetworkStatistics loadNetworkStatistics() throws IOException, InterruptedException { - final Process nstatProcess = Runtime.getRuntime().exec(NSTAT_COMMAND_LINE); - - if (nstatProcess.waitFor() == 0) { - return OBJECT_MAPPER.readValue(nstatProcess.getInputStream(), NetworkStatistics.class); - } else { - throw new IOException("nstat process did not exit normally"); - } - } -} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/metrics/NstatCountersTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/metrics/NstatCountersTest.java deleted file mode 100644 index 3534b576..00000000 --- a/service/src/test/java/org/whispersystems/textsecuregcm/metrics/NstatCountersTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2021 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.metrics; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.io.IOException; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledOnOs; -import org.junit.jupiter.api.condition.OS; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.whispersystems.textsecuregcm.metrics.NstatCounters.NetworkStatistics; - -class NstatCountersTest { - - @Test - @EnabledOnOs(OS.LINUX) - void loadNetworkStatistics() throws IOException, InterruptedException { - final NetworkStatistics networkStatistics = NstatCounters.loadNetworkStatistics(); - - assertNotNull(networkStatistics.getKernelStatistics()); - assertFalse(networkStatistics.getKernelStatistics().isEmpty()); - } - - @ParameterizedTest - @MethodSource("shouldIncludeMetricNameProvider") - void shouldIncludeMetric(final String metricName, final boolean expectInclude) { - assertEquals(expectInclude, NstatCounters.shouldIncludeMetric(metricName)); - } - - static Stream shouldIncludeMetricNameProvider() { - return Stream.of(Arguments.of("IpInReceives", true), - Arguments.of("TcpActiveOpens", true), - Arguments.of("UdpInDatagrams", false), - Arguments.of("Ip6InReceives", false), - Arguments.of("Udp6InDatagrams", false), - Arguments.of("TcpExtSyncookiesSent", true), - Arguments.of("IpExtInNoRoutes", true)); - } -}