diff --git a/.github/workflows/run-integration-tests.yml b/.github/workflows/run-integration-tests.yml index 181fd83a50..79518ec0de 100644 --- a/.github/workflows/run-integration-tests.yml +++ b/.github/workflows/run-integration-tests.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - integration-test: [ "checkstyle", "metrics" ] + integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ] steps: - name: Install Harden-Runner uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 @@ -27,13 +27,19 @@ jobs: disable-sudo: true egress-policy: block allowed-endpoints: > + # XXX: After updating the validation build flags in + # `integration-tests/prometheus-java-client.sh`, review whether the + # Docker domains specified here can be dropped. api.adoptium.net:443 + auth.docker.io:443 checkstyle.org:443 example.com:80 github.com:443 objects.githubusercontent.com:443 oss.sonatype.org:443 + production.cloudflare.docker.com:443 raw.githubusercontent.com:443 + registry-1.docker.io:443 repo.maven.apache.org:443 repository.sonatype.org:443 - name: Check out code and set up JDK and Maven diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitMethodDeclaration.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitMethodDeclaration.java index 24fbfa3992..9415efb68e 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitMethodDeclaration.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitMethodDeclaration.java @@ -101,6 +101,8 @@ private void reportMethodRenameBlocker(MethodTree tree, String reason, VisitorSt .build()); } + // XXX: Consider dropping leading underscores that otherwise result when canonicalizing + // `test_some_method_name`. private static Optional tryCanonicalizeMethodName(MethodSymbol symbol) { return Optional.of(symbol.getQualifiedName().toString()) .filter(name -> name.startsWith(TEST_PREFIX)) diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java index 99b3380df3..9061a82c9d 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java @@ -36,7 +36,9 @@ */ // XXX: What about `v1 + "sep" + v2` and similar expressions? Do we want to rewrite those to // `String.join`, or should some `String.join` invocations be rewritten to use the `+` operator? -// (The latter suggestion would conflict with the `FormatStringConcatenation` check.) +// (The latter suggestion would conflict with the `FormatStringConcatenation` check, but does make +// more sense when `"sep"` is a long string. Similarly for `String.format("%s some long text %s", +// arg1, arg2)`.) @AutoService(BugChecker.class) @BugPattern( summary = "Prefer `String#join` over `String#format`", diff --git a/integration-tests/prometheus-java-client-expected-changes.patch b/integration-tests/prometheus-java-client-expected-changes.patch new file mode 100644 index 0000000000..8c83b749c3 --- /dev/null +++ b/integration-tests/prometheus-java-client-expected-changes.patch @@ -0,0 +1,10363 @@ +--- a/integration-tests/it-common/src/test/java/io/prometheus/client/it/common/ExporterTest.java ++++ b/integration-tests/it-common/src/test/java/io/prometheus/client/it/common/ExporterTest.java +@@ -111,7 +111,7 @@ public abstract class ExporterTest { + if (exception != null) { + exception.printStackTrace(); + } +- fail("timeout while getting metrics from " + url); ++ fail("timeout while getting metrics from %s", url); + return null; // will not happen + } + +--- a/integration-tests/it-common/src/test/java/io/prometheus/client/it/common/Volume.java ++++ b/integration-tests/it-common/src/test/java/io/prometheus/client/it/common/Volume.java +@@ -8,6 +8,7 @@ import java.io.File; + import java.io.IOException; + import java.net.URISyntaxException; + import java.nio.file.*; ++import java.nio.file.Path; + import java.nio.file.attribute.BasicFileAttributes; + import java.util.function.Predicate; + +@@ -21,7 +22,7 @@ public class Volume { + } + + public static Volume create(String prefix) throws IOException, URISyntaxException { +- Path targetDir = Paths.get(Volume.class.getResource("/").toURI()).getParent(); ++ Path targetDir = Path.of(Volume.class.getResource("/").toURI()).getParent(); + assertThat(targetDir.getFileName().toString()) + .as("failed to locate target/ directory") + .isEqualTo("target"); +@@ -61,7 +62,7 @@ public class Volume { + } + }); + } else { +- fail(src + ": No such file or directory"); ++ fail("%s: No such file or directory", src); + } + return this; + } +--- a/integration-tests/it-exporter/it-exporter-test/src/test/java/io/prometheus/metrics/it/exporter/test/ExporterIT.java ++++ b/integration-tests/it-exporter/it-exporter-test/src/test/java/io/prometheus/metrics/it/exporter/test/ExporterIT.java +@@ -87,12 +87,12 @@ abstract class ExporterIT extends ExporterTest { + assertThat(metrics.get(2).getName()).isEqualTo("uptime_seconds_total"); + } + +- @ParameterizedTest + @CsvSource({ + "openmetrics, debug-openmetrics.txt", +- "text, debug-text.txt", + "prometheus-protobuf, debug-protobuf.txt", ++ "text, debug-text.txt" + }) ++ @ParameterizedTest + public void testPrometheusProtobufDebugFormat(String format, String expected) throws IOException { + start(); + Response response = scrape("GET", "debug=" + format); +@@ -147,7 +147,7 @@ abstract class ExporterIT extends ExporterTest { + start(); + Response fullResponse = scrape("GET", ""); + int size = fullResponse.body.length; +- assertThat(size).isGreaterThan(0); ++ assertThat(size).isPositive(); + Response headResponse = scrape("HEAD", ""); + assertThat(headResponse.status).isEqualTo(200); + assertThat(headResponse.getHeader("Content-Length")).isEqualTo(Integer.toString(size)); +--- a/integration-tests/it-exporter/it-no-protobuf-test/src/test/java/io/prometheus/metrics/it/noprotobuf/NoProtobufIT.java ++++ b/integration-tests/it-exporter/it-no-protobuf-test/src/test/java/io/prometheus/metrics/it/noprotobuf/NoProtobufIT.java +@@ -7,14 +7,14 @@ import java.io.IOException; + import java.net.URISyntaxException; + import org.junit.jupiter.api.Test; + +-class NoProtobufIT extends ExporterTest { ++final class NoProtobufIT extends ExporterTest { + + public NoProtobufIT() throws IOException, URISyntaxException { + super("exporter-no-protobuf"); + } + + @Test +- public void testPrometheusProtobufDebugFormat() throws IOException { ++ void prometheusProtobufDebugFormat() throws IOException { + start(); + assertThat(scrape("GET", "debug=text").status).isEqualTo(200); + // protobuf is not supported +--- a/integration-tests/it-pushgateway/src/test/java/io/prometheus/metrics/it/pushgateway/PushGatewayIT.java ++++ b/integration-tests/it-pushgateway/src/test/java/io/prometheus/metrics/it/pushgateway/PushGatewayIT.java +@@ -22,7 +22,7 @@ import org.testcontainers.containers.Network; + import org.testcontainers.containers.wait.strategy.Wait; + import org.testcontainers.utility.MountableFile; + +-public class PushGatewayIT { ++final class PushGatewayIT { + + private GenericContainer sampleAppContainer; + private GenericContainer pushGatewayContainer; +@@ -30,7 +30,7 @@ public class PushGatewayIT { + private Volume sampleAppVolume; + + @BeforeEach +- public void setUp() throws IOException, URISyntaxException { ++ void setUp() throws IOException, URISyntaxException { + Network network = Network.newNetwork(); + sampleAppVolume = Volume.create("it-pushgateway").copy("pushgateway-test-app.jar"); + pushGatewayContainer = +@@ -56,7 +56,7 @@ public class PushGatewayIT { + } + + @AfterEach +- public void tearDown() throws IOException { ++ void tearDown() throws IOException { + prometheusContainer.stop(); + pushGatewayContainer.stop(); + sampleAppContainer.stop(); +@@ -66,7 +66,7 @@ public class PushGatewayIT { + final OkHttpClient client = new OkHttpClient(); + + @Test +- public void testSimple() throws IOException, InterruptedException { ++ void simple() throws IOException, InterruptedException { + pushGatewayContainer.start(); + sampleAppContainer + .withCommand( +@@ -86,7 +86,7 @@ public class PushGatewayIT { + } + + @Test +- public void testTextFormat() throws IOException, InterruptedException { ++ void textFormat() throws IOException, InterruptedException { + pushGatewayContainer.start(); + sampleAppContainer + .withCommand( +@@ -106,7 +106,7 @@ public class PushGatewayIT { + } + + @Test +- public void testBasicAuth() throws IOException, InterruptedException { ++ void basicAuth() throws IOException, InterruptedException { + pushGatewayContainer + .withCopyFileToContainer( + MountableFile.forClasspathResource("/pushgateway-basicauth.yaml"), +@@ -131,7 +131,7 @@ public class PushGatewayIT { + } + + @Test +- public void testSsl() throws InterruptedException, IOException { ++ void ssl() throws InterruptedException, IOException { + pushGatewayContainer + .withCopyFileToContainer( + MountableFile.forClasspathResource("/pushgateway-ssl.yaml"), +@@ -156,7 +156,7 @@ public class PushGatewayIT { + } + + @Test +- public void testProtobuf() throws IOException, InterruptedException { ++ void protobuf() throws IOException, InterruptedException { + pushGatewayContainer.start(); + sampleAppContainer + .withCommand( +@@ -197,7 +197,7 @@ public class PushGatewayIT { + JSONArray result = + JsonPath.parse(scrapeResponseJson) + .read("$.data.result" + Filter.filter(criteria) + ".value[1]"); +- assertThat(result.size()).isOne(); ++ assertThat(result).hasSize(1); + return Double.parseDouble(result.get(0).toString()); + } + +@@ -244,7 +244,7 @@ public class PushGatewayIT { + Thread.sleep(250); + timeRemaining -= 250; + } +- fail("timeout while scraping " + url); ++ fail("timeout while scraping %s", url); + return null; + } + +@@ -253,13 +253,7 @@ public class PushGatewayIT { + long waitTimeMillis = 0; + while (container.isRunning()) { + if (waitTimeMillis > unit.toMillis(timeout)) { +- fail( +- container.getContainerName() +- + " did not terminate after " +- + timeout +- + " " +- + unit +- + "."); ++ fail("%s did not terminate after %s %s.", container.getContainerName(), timeout, unit); + } + Thread.sleep(20); + waitTimeMillis += 20; +--- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterFilterProperties.java ++++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterFilterProperties.java +@@ -1,8 +1,9 @@ + package io.prometheus.metrics.config; + ++import static java.util.Collections.unmodifiableList; ++ + import java.util.ArrayList; + import java.util.Arrays; +-import java.util.Collections; + import java.util.List; + import java.util.Map; + +@@ -26,17 +27,13 @@ public class ExporterFilterProperties { + List allowedPrefixes, + List excludedPrefixes) { + this.allowedNames = +- allowedNames == null ? null : Collections.unmodifiableList(new ArrayList<>(allowedNames)); ++ allowedNames == null ? null : unmodifiableList(new ArrayList<>(allowedNames)); + this.excludedNames = +- excludedNames == null ? null : Collections.unmodifiableList(new ArrayList<>(excludedNames)); ++ excludedNames == null ? null : unmodifiableList(new ArrayList<>(excludedNames)); + this.allowedPrefixes = +- allowedPrefixes == null +- ? null +- : Collections.unmodifiableList(new ArrayList<>(allowedPrefixes)); ++ allowedPrefixes == null ? null : unmodifiableList(new ArrayList<>(allowedPrefixes)); + this.excludedPrefixes = +- excludedPrefixes == null +- ? null +- : Collections.unmodifiableList(new ArrayList<>(excludedPrefixes)); ++ excludedPrefixes == null ? null : unmodifiableList(new ArrayList<>(excludedPrefixes)); + } + + public List getAllowedMetricNames() { +--- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterOpenTelemetryProperties.java ++++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterOpenTelemetryProperties.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.config; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.HashMap; + import java.util.Map; + +@@ -145,10 +147,10 @@ public class ExporterOpenTelemetryProperties { + private Builder() {} + + public Builder protocol(String protocol) { +- if (!protocol.equals("grpc") && !protocol.equals("http/protobuf")) { +- throw new IllegalArgumentException( +- protocol + ": Unsupported protocol. Expecting grpc or http/protobuf"); +- } ++ checkArgument( ++ protocol.equals("grpc") || protocol.equals("http/protobuf"), ++ "%s: Unsupported protocol. Expecting grpc or http/protobuf", ++ protocol); + this.protocol = protocol; + return this; + } +@@ -165,17 +167,13 @@ public class ExporterOpenTelemetryProperties { + } + + public Builder intervalSeconds(int intervalSeconds) { +- if (intervalSeconds <= 0) { +- throw new IllegalArgumentException(intervalSeconds + ": Expecting intervalSeconds > 0"); +- } ++ checkArgument(intervalSeconds > 0, "%s: Expecting intervalSeconds > 0", intervalSeconds); + this.interval = intervalSeconds + "s"; + return this; + } + + public Builder timeoutSeconds(int timeoutSeconds) { +- if (timeoutSeconds <= 0) { +- throw new IllegalArgumentException(timeoutSeconds + ": Expecting timeoutSeconds > 0"); +- } ++ checkArgument(timeoutSeconds > 0, "%s: Expecting timeoutSeconds > 0", timeoutSeconds); + this.timeout = timeoutSeconds + "s"; + return this; + } +--- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/MetricsProperties.java ++++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/MetricsProperties.java +@@ -2,8 +2,8 @@ package io.prometheus.metrics.config; + + import static java.util.Collections.unmodifiableList; + ++import com.google.common.collect.ImmutableList; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.Map; + +@@ -301,7 +301,7 @@ public class MetricsProperties { + public List getSummaryQuantileErrors() { + if (summaryQuantiles != null) { + if (summaryQuantileErrors == null) { +- return Collections.emptyList(); ++ return ImmutableList.of(); + } + } + return summaryQuantileErrors; +--- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusProperties.java ++++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusProperties.java +@@ -10,7 +10,7 @@ import java.util.Map; + */ + public class PrometheusProperties { + +- private static final PrometheusProperties instance = PrometheusPropertiesLoader.load(); ++ private static final PrometheusProperties INSTANCE = PrometheusPropertiesLoader.load(); + + private final MetricsProperties defaultMetricsProperties; + private final Map metricProperties = new HashMap<>(); +@@ -33,7 +33,7 @@ public class PrometheusProperties { + * + */ + public static PrometheusProperties get() throws PrometheusPropertiesException { +- return instance; ++ return INSTANCE; + } + + public PrometheusProperties( +--- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusPropertiesLoader.java ++++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/PrometheusPropertiesLoader.java +@@ -3,7 +3,7 @@ package io.prometheus.metrics.config; + import java.io.IOException; + import java.io.InputStream; + import java.nio.file.Files; +-import java.nio.file.Paths; ++import java.nio.file.Path; + import java.util.HashMap; + import java.util.HashSet; + import java.util.Map; +@@ -126,7 +126,7 @@ public class PrometheusPropertiesLoader { + path = System.getenv("PROMETHEUS_CONFIG"); + } + if (path != null) { +- try (InputStream stream = Files.newInputStream(Paths.get(path))) { ++ try (InputStream stream = Files.newInputStream(Path.of(path))) { + properties.load(stream); + } catch (IOException e) { + throw new PrometheusPropertiesException( +--- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/Util.java ++++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/Util.java +@@ -23,7 +23,7 @@ class Util { + if (property != null) { + if (!"true".equalsIgnoreCase(property) && !"false".equalsIgnoreCase(property)) { + throw new PrometheusPropertiesException( +- String.format("%s: Expecting 'true' or 'false'. Found: %s", name, property)); ++ String.join(": Expecting 'true' or 'false'. Found: ", name, property)); + } + return Boolean.parseBoolean(property); + } +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExemplarsPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExemplarsPropertiesTest.java +@@ -1,39 +1,46 @@ + package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class ExemplarsPropertiesTest { ++final class ExemplarsPropertiesTest { + + @Test + void load() { + ExemplarsProperties properties = + load( +- Map.of( +- "io.prometheus.exemplars.minRetentionPeriodSeconds", "1", +- "io.prometheus.exemplars.maxRetentionPeriodSeconds", "2", +- "io.prometheus.exemplars.sampleIntervalMilliseconds", "3")); +- assertThat(properties.getMinRetentionPeriodSeconds()).isOne(); ++ ImmutableMap.of( ++ "io.prometheus.exemplars.minRetentionPeriodSeconds", ++ "1", ++ "io.prometheus.exemplars.maxRetentionPeriodSeconds", ++ "2", ++ "io.prometheus.exemplars.sampleIntervalMilliseconds", ++ "3")); ++ assertThat(properties.getMinRetentionPeriodSeconds()).isEqualTo(1); + assertThat(properties.getMaxRetentionPeriodSeconds()).isEqualTo(2); + assertThat(properties.getSampleIntervalMilliseconds()).isEqualTo(3); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> load(Map.of("io.prometheus.exemplars.minRetentionPeriodSeconds", "-1"))) +- .withMessage( ++ assertThatThrownBy( ++ () -> load(ImmutableMap.of("io.prometheus.exemplars.minRetentionPeriodSeconds", "-1"))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "io.prometheus.exemplars.minRetentionPeriodSeconds: Expecting value > 0. Found: -1"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> load(Map.of("io.prometheus.exemplars.maxRetentionPeriodSeconds", "0"))) +- .withMessage( ++ assertThatThrownBy( ++ () -> load(ImmutableMap.of("io.prometheus.exemplars.maxRetentionPeriodSeconds", "0"))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "io.prometheus.exemplars.maxRetentionPeriodSeconds: Expecting value > 0. Found: 0"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> load(Map.of("io.prometheus.exemplars.sampleIntervalMilliseconds", "-1"))) +- .withMessage( ++ assertThatThrownBy( ++ () -> load(ImmutableMap.of("io.prometheus.exemplars.sampleIntervalMilliseconds", "-1"))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "io.prometheus.exemplars.sampleIntervalMilliseconds: Expecting value > 0. Found: -1"); + } + +@@ -49,7 +56,7 @@ class ExemplarsPropertiesTest { + .maxRetentionPeriodSeconds(2) + .sampleIntervalMilliseconds(3) + .build(); +- assertThat(properties.getMinRetentionPeriodSeconds()).isOne(); ++ assertThat(properties.getMinRetentionPeriodSeconds()).isEqualTo(1); + assertThat(properties.getMaxRetentionPeriodSeconds()).isEqualTo(2); + assertThat(properties.getSampleIntervalMilliseconds()).isEqualTo(3); + } +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterFilterPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterFilterPropertiesTest.java +@@ -2,21 +2,26 @@ package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; + ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class ExporterFilterPropertiesTest { ++final class ExporterFilterPropertiesTest { + + @Test + void load() { + ExporterFilterProperties properties = + load( +- Map.of( +- "io.prometheus.exporter.filter.metricNameMustBeEqualTo", "a,b,c", +- "io.prometheus.exporter.filter.metricNameMustNotBeEqualTo", "d,e,f", +- "io.prometheus.exporter.filter.metricNameMustStartWith", "g,h,i", +- "io.prometheus.exporter.filter.metricNameMustNotStartWith", "j,k,l")); ++ ImmutableMap.of( ++ "io.prometheus.exporter.filter.metricNameMustBeEqualTo", ++ "a,b,c", ++ "io.prometheus.exporter.filter.metricNameMustNotBeEqualTo", ++ "d,e,f", ++ "io.prometheus.exporter.filter.metricNameMustStartWith", ++ "g,h,i", ++ "io.prometheus.exporter.filter.metricNameMustNotStartWith", ++ "j,k,l")); + assertThat(properties.getAllowedMetricNames()).containsExactly("a", "b", "c"); + assertThat(properties.getExcludedMetricNames()).containsExactly("d", "e", "f"); + assertThat(properties.getAllowedMetricNamePrefixes()).containsExactly("g", "h", "i"); +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterHttpServerPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterHttpServerPropertiesTest.java +@@ -1,27 +1,28 @@ + package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class ExporterHttpServerPropertiesTest { ++final class ExporterHttpServerPropertiesTest { + @Test + void load() { + ExporterHttpServerProperties properties = +- load(Map.of("io.prometheus.exporter.httpServer.port", "1")); +- assertThat(properties.getPort()).isOne(); ++ load(ImmutableMap.of("io.prometheus.exporter.httpServer.port", "1")); ++ assertThat(properties.getPort()).isEqualTo(1); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> load(Map.of("io.prometheus.exporter.httpServer.port", "0"))) +- .withMessage("io.prometheus.exporter.httpServer.port: Expecting value > 0. Found: 0"); ++ assertThatThrownBy(() -> load(ImmutableMap.of("io.prometheus.exporter.httpServer.port", "0"))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage("io.prometheus.exporter.httpServer.port: Expecting value > 0. Found: 0"); + } + + @Test + void builder() { +- assertThat(ExporterHttpServerProperties.builder().port(1).build().getPort()).isOne(); ++ assertThat(ExporterHttpServerProperties.builder().port(1).build().getPort()).isEqualTo(1); + } + + private static ExporterHttpServerProperties load(Map map) { +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterOpenTelemetryPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterOpenTelemetryPropertiesTest.java +@@ -2,11 +2,12 @@ package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; + ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class ExporterOpenTelemetryPropertiesTest { ++final class ExporterOpenTelemetryPropertiesTest { + + @Test + void load() { +@@ -32,7 +33,7 @@ class ExporterOpenTelemetryPropertiesTest { + assertThat(properties.getProtocol()).isEqualTo("grpc"); + assertThat(properties.getEndpoint()).isEqualTo("http://localhost:8080"); + assertThat(properties.getHeaders()) +- .containsExactlyInAnyOrderEntriesOf(Map.of("key1", "value1", "key2", "value2")); ++ .containsExactlyInAnyOrderEntriesOf(ImmutableMap.of("key1", "value1", "key2", "value2")); + assertThat(properties.getInterval()).isEqualTo("10s"); + assertThat(properties.getTimeout()).isEqualTo("5s"); + assertThat(properties.getServiceName()).isEqualTo("serviceName"); +@@ -40,7 +41,7 @@ class ExporterOpenTelemetryPropertiesTest { + assertThat(properties.getServiceInstanceId()).isEqualTo("serviceInstanceId"); + assertThat(properties.getServiceVersion()).isEqualTo("serviceVersion"); + assertThat(properties.getResourceAttributes()) +- .containsExactlyInAnyOrderEntriesOf(Map.of("key1", "value1", "key2", "value2")); ++ .containsExactlyInAnyOrderEntriesOf(ImmutableMap.of("key1", "value1", "key2", "value2")); + } + + private static ExporterOpenTelemetryProperties load(Map map) { +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterPropertiesTest.java +@@ -1,40 +1,45 @@ + package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class ExporterPropertiesTest { ++final class ExporterPropertiesTest { + + @Test + void load() { + ExporterProperties properties = + load( + new HashMap<>( +- Map.of( +- "io.prometheus.exporter.includeCreatedTimestamps", "true", +- "io.prometheus.exporter.exemplarsOnAllMetricTypes", "true"))); ++ ImmutableMap.of( ++ "io.prometheus.exporter.includeCreatedTimestamps", ++ "true", ++ "io.prometheus.exporter.exemplarsOnAllMetricTypes", ++ "true"))); + assertThat(properties.getIncludeCreatedTimestamps()).isTrue(); + assertThat(properties.getExemplarsOnAllMetricTypes()).isTrue(); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + load( + new HashMap<>( +- Map.of("io.prometheus.exporter.includeCreatedTimestamps", "invalid")))) +- .withMessage( ++ ImmutableMap.of( ++ "io.prometheus.exporter.includeCreatedTimestamps", "invalid")))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "io.prometheus.exporter.includeCreatedTimestamps: Expecting 'true' or 'false'. Found: invalid"); +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + load( + new HashMap<>( +- Map.of("io.prometheus.exporter.exemplarsOnAllMetricTypes", "invalid")))) +- .withMessage( ++ ImmutableMap.of( ++ "io.prometheus.exporter.exemplarsOnAllMetricTypes", "invalid")))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "io.prometheus.exporter.exemplarsOnAllMetricTypes: Expecting 'true' or 'false'. Found: invalid"); + } + +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterPushgatewayPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/ExporterPushgatewayPropertiesTest.java +@@ -1,30 +1,35 @@ + package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class ExporterPushgatewayPropertiesTest { ++final class ExporterPushgatewayPropertiesTest { + + @Test + void load() { + ExporterPushgatewayProperties properties = + load( +- Map.of( +- "io.prometheus.exporter.pushgateway.address", "http://localhost", +- "io.prometheus.exporter.pushgateway.job", "job", +- "io.prometheus.exporter.pushgateway.scheme", "http")); ++ ImmutableMap.of( ++ "io.prometheus.exporter.pushgateway.address", ++ "http://localhost", ++ "io.prometheus.exporter.pushgateway.job", ++ "job", ++ "io.prometheus.exporter.pushgateway.scheme", ++ "http")); + + assertThat(properties.getAddress()).isEqualTo("http://localhost"); + assertThat(properties.getJob()).isEqualTo("job"); + assertThat(properties.getScheme()).isEqualTo("http"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> load(Map.of("io.prometheus.exporter.pushgateway.scheme", "foo"))) +- .withMessage( ++ assertThatThrownBy( ++ () -> load(ImmutableMap.of("io.prometheus.exporter.pushgateway.scheme", "foo"))) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "io.prometheus.exporter.pushgateway.scheme: Illegal value. Expecting 'http' or 'https'. Found: foo"); + } + +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/MetricsPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/MetricsPropertiesTest.java +@@ -1,11 +1,11 @@ + package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import org.junit.jupiter.api.Test; + +-class MetricsPropertiesTest { ++final class MetricsPropertiesTest { + @Test + void builder() { + assertThat(MetricsProperties.builder().exemplarsEnabled(true).build().getExemplarsEnabled()) +@@ -30,7 +30,7 @@ class MetricsPropertiesTest { + .containsExactly(0.1, 0.2); + assertThat( + MetricsProperties.builder().summaryMaxAgeSeconds(1L).build().getSummaryMaxAgeSeconds()) +- .isOne(); ++ .isEqualTo(1); + assertThat( + MetricsProperties.builder() + .summaryQuantiles(0.2) +@@ -43,38 +43,38 @@ class MetricsPropertiesTest { + .summaryNumberOfAgeBuckets(1) + .build() + .getSummaryNumberOfAgeBuckets()) +- .isOne(); ++ .isEqualTo(1); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().summaryNumberOfAgeBuckets(0).build()) +- .withMessage(".summaryNumberOfAgeBuckets: Expecting value > 0. Found: 0"); ++ assertThatThrownBy(() -> MetricsProperties.builder().summaryNumberOfAgeBuckets(0).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".summaryNumberOfAgeBuckets: Expecting value > 0. Found: 0"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().summaryQuantiles(2L).build()) +- .withMessage(".summaryQuantiles: Expecting 0.0 <= quantile <= 1.0. Found: 2.0"); ++ assertThatThrownBy(() -> MetricsProperties.builder().summaryQuantiles(2L).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".summaryQuantiles: Expecting 0.0 <= quantile <= 1.0. Found: 2.0"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().summaryQuantileErrors(0.9).build()) +- .withMessage( ++ assertThatThrownBy(() -> MetricsProperties.builder().summaryQuantileErrors(0.9).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + ".summaryQuantileErrors: Can't configure summaryQuantileErrors without configuring summaryQuantiles"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + MetricsProperties.builder() + .summaryQuantiles(0.1) + .summaryQuantileErrors(0.1, 0.9) + .build()) +- .withMessage(".summaryQuantileErrors: must have the same length as summaryQuantiles"); ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".summaryQuantileErrors: must have the same length as summaryQuantiles"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + MetricsProperties.builder() + .summaryQuantiles(0.1) + .summaryQuantileErrors(-0.9) + .build()) +- .withMessage(".summaryQuantileErrors: Expecting 0.0 <= error <= 1.0"); ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".summaryQuantileErrors: Expecting 0.0 <= error <= 1.0"); + } + + @Test +@@ -84,7 +84,7 @@ class MetricsPropertiesTest { + .histogramNativeInitialSchema(1) + .build() + .getHistogramNativeInitialSchema()) +- .isOne(); ++ .isEqualTo(1); + assertThat( + MetricsProperties.builder() + .histogramNativeMinZeroThreshold(.1) +@@ -102,53 +102,55 @@ class MetricsPropertiesTest { + .histogramNativeMaxNumberOfBuckets(1) + .build() + .getHistogramNativeMaxNumberOfBuckets()) +- .isOne(); ++ .isEqualTo(1); + assertThat( + MetricsProperties.builder() + .histogramNativeResetDurationSeconds(1L) + .build() + .getHistogramNativeResetDurationSeconds()) +- .isOne(); ++ .isEqualTo(1); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().histogramNativeInitialSchema(10).build()) +- .withMessage( +- ".histogramNativeInitialSchema: Expecting number between -4 and +8. Found: 10"); ++ assertThatThrownBy(() -> MetricsProperties.builder().histogramNativeInitialSchema(10).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".histogramNativeInitialSchema: Expecting number between -4 and +8. Found: 10"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().histogramNativeMinZeroThreshold(-1.0).build()) +- .withMessage(".histogramNativeMinZeroThreshold: Expecting value >= 0. Found: -1.0"); ++ assertThatThrownBy( ++ () -> MetricsProperties.builder().histogramNativeMinZeroThreshold(-1.0).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".histogramNativeMinZeroThreshold: Expecting value >= 0. Found: -1.0"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().histogramNativeMaxZeroThreshold(-1.0).build()) +- .withMessage(".histogramNativeMaxZeroThreshold: Expecting value >= 0. Found: -1.0"); ++ assertThatThrownBy( ++ () -> MetricsProperties.builder().histogramNativeMaxZeroThreshold(-1.0).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".histogramNativeMaxZeroThreshold: Expecting value >= 0. Found: -1.0"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy(() -> MetricsProperties.builder().histogramNativeMaxNumberOfBuckets(-1).build()) +- .withMessage(".histogramNativeMaxNumberOfBuckets: Expecting value >= 0. Found: -1"); ++ assertThatThrownBy( ++ () -> MetricsProperties.builder().histogramNativeMaxNumberOfBuckets(-1).build()) ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".histogramNativeMaxNumberOfBuckets: Expecting value >= 0. Found: -1"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> MetricsProperties.builder().histogramNativeResetDurationSeconds(-1L).build()) +- .withMessage(".histogramNativeResetDurationSeconds: Expecting value >= 0. Found: -1"); ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".histogramNativeResetDurationSeconds: Expecting value >= 0. Found: -1"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + MetricsProperties.builder() + .histogramNativeOnly(true) + .histogramClassicOnly(true) + .build()) +- .withMessage(".histogramNativeOnly and .histogramClassicOnly cannot both be true"); ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage(".histogramNativeOnly and .histogramClassicOnly cannot both be true"); + +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + MetricsProperties.builder() + .histogramNativeMinZeroThreshold(0.1) + .histogramNativeMaxZeroThreshold(0.01) + .build()) +- .withMessage( ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + ".histogramNativeMinZeroThreshold cannot be greater than .histogramNativeMaxZeroThreshold"); + } + } +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/PrometheusPropertiesLoaderTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/PrometheusPropertiesLoaderTest.java +@@ -1,17 +1,17 @@ + package io.prometheus.metrics.config; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import java.util.Properties; + import org.junit.jupiter.api.Test; + import org.junitpioneer.jupiter.SetSystemProperty; + + /** Tests for {@link PrometheusPropertiesLoader}. */ +-class PrometheusPropertiesLoaderTest { ++final class PrometheusPropertiesLoaderTest { + + @Test +- public void propertiesShouldBeLoadedFromPropertiesFile() { ++ void propertiesShouldBeLoadedFromPropertiesFile() { + PrometheusProperties prometheusProperties = PrometheusPropertiesLoader.load(); + assertThat(prometheusProperties.getDefaultMetricProperties().getHistogramClassicUpperBounds()) + .hasSize(11); +@@ -24,20 +24,20 @@ class PrometheusPropertiesLoaderTest { + .isTrue(); + } + +- @Test + @SetSystemProperty(key = "prometheus.config", value = "nonexistent.properties") ++ @Test + void cantLoadPropertiesFile() { +- assertThatExceptionOfType(PrometheusPropertiesException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> { + PrometheusPropertiesLoader.load(new Properties()); + }) +- .withMessage( ++ .isInstanceOf(PrometheusPropertiesException.class) ++ .hasMessage( + "Failed to read Prometheus properties from nonexistent.properties: nonexistent.properties"); + } + + @Test +- public void externalPropertiesShouldOverridePropertiesFile() { ++ void externalPropertiesShouldOverridePropertiesFile() { + Properties properties = new Properties(); + properties.setProperty("io.prometheus.metrics.histogramClassicUpperBounds", ".005, .01"); + properties.setProperty( +--- a/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/PrometheusPropertiesTest.java ++++ b/prometheus-metrics-config/src/test/java/io/prometheus/metrics/config/PrometheusPropertiesTest.java +@@ -7,10 +7,10 @@ import java.io.InputStream; + import java.util.Properties; + import org.junit.jupiter.api.Test; + +-class PrometheusPropertiesTest { ++final class PrometheusPropertiesTest { + + @Test +- public void testPrometheusConfig() { ++ void prometheusConfig() { + PrometheusProperties result = PrometheusProperties.get(); + assertThat(result.getDefaultMetricProperties().getHistogramClassicUpperBounds()).hasSize(11); + assertThat(result.getMetricProperties("http_duration_seconds").getHistogramClassicUpperBounds()) +@@ -18,7 +18,7 @@ class PrometheusPropertiesTest { + } + + @Test +- public void testEmptyUpperBounds() throws IOException { ++ void emptyUpperBounds() throws IOException { + Properties properties = new Properties(); + try (InputStream stream = + Thread.currentThread() +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/exemplars/ExemplarSamplerConfig.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/exemplars/ExemplarSamplerConfig.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.core.exemplars; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import io.prometheus.metrics.config.ExemplarsProperties; + import io.prometheus.metrics.config.PrometheusProperties; + import java.util.concurrent.TimeUnit; +@@ -78,36 +80,31 @@ public class ExemplarSamplerConfig { + } + + private void validate() { +- if (minRetentionPeriodMillis <= 0) { +- throw new IllegalArgumentException( +- minRetentionPeriodMillis + ": minRetentionPeriod must be > 0."); +- } +- if (maxRetentionPeriodMillis <= 0) { +- throw new IllegalArgumentException( +- maxRetentionPeriodMillis + ": maxRetentionPeriod must be > 0."); +- } ++ checkArgument( ++ minRetentionPeriodMillis > 0, ++ "%s: minRetentionPeriod must be > 0.", ++ minRetentionPeriodMillis); ++ checkArgument( ++ maxRetentionPeriodMillis > 0, ++ "%s: maxRetentionPeriod must be > 0.", ++ maxRetentionPeriodMillis); + if (histogramClassicUpperBounds != null) { +- if (histogramClassicUpperBounds.length == 0 +- || histogramClassicUpperBounds[histogramClassicUpperBounds.length - 1] +- != Double.POSITIVE_INFINITY) { +- throw new IllegalArgumentException( +- "histogramClassicUpperBounds must contain the +Inf bucket."); +- } +- if (histogramClassicUpperBounds.length != numberOfExemplars) { +- throw new IllegalArgumentException( +- "histogramClassicUpperBounds.length must be equal to numberOfExemplars."); +- } ++ checkArgument( ++ histogramClassicUpperBounds.length != 0 ++ && histogramClassicUpperBounds[histogramClassicUpperBounds.length - 1] ++ == Double.POSITIVE_INFINITY, ++ "histogramClassicUpperBounds must contain the +Inf bucket."); ++ checkArgument( ++ histogramClassicUpperBounds.length == numberOfExemplars, ++ "histogramClassicUpperBounds.length must be equal to numberOfExemplars."); + double bound = histogramClassicUpperBounds[0]; + for (int i = 1; i < histogramClassicUpperBounds.length; i++) { +- if (bound >= histogramClassicUpperBounds[i]) { +- throw new IllegalArgumentException( +- "histogramClassicUpperBounds must be sorted and must not contain duplicates."); +- } ++ checkArgument( ++ bound < histogramClassicUpperBounds[i], ++ "histogramClassicUpperBounds must be sorted and must not contain duplicates."); + } + } +- if (numberOfExemplars <= 0) { +- throw new IllegalArgumentException(numberOfExemplars + ": numberOfExemplars must be > 0."); +- } ++ checkArgument(numberOfExemplars > 0, "%s: numberOfExemplars must be > 0.", numberOfExemplars); + } + + private static T getOrDefault(T result, T defaultValue) { +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Buffer.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Buffer.java +@@ -17,7 +17,7 @@ import java.util.function.Supplier; + */ + class Buffer { + +- private static final long bufferActiveBit = 1L << 63; ++ private static final long BUFFER_ACTIVE_BIT = 1L << 63; + private final AtomicLong observationCount = new AtomicLong(0); + private double[] observationBuffer = new double[0]; + private int bufferPos = 0; +@@ -29,7 +29,7 @@ class Buffer { + + boolean append(double value) { + long count = observationCount.incrementAndGet(); +- if ((count & bufferActiveBit) == 0) { ++ if ((count & BUFFER_ACTIVE_BIT) == 0) { + return false; // sign bit not set -> buffer not active. + } else { + doAppend(value); +@@ -69,7 +69,7 @@ class Buffer { + runLock.lock(); + try { + // Signal that the buffer is active. +- Long expectedCount = observationCount.getAndAdd(bufferActiveBit); ++ Long expectedCount = observationCount.getAndAdd(BUFFER_ACTIVE_BIT); + + while (!complete.apply(expectedCount)) { + // Wait until all in-flight threads have added their observations to the histogram / +@@ -84,10 +84,10 @@ class Buffer { + int expectedBufferSize; + if (reset) { + expectedBufferSize = +- (int) ((observationCount.getAndSet(0) & ~bufferActiveBit) - expectedCount); ++ (int) ((observationCount.getAndSet(0) & ~BUFFER_ACTIVE_BIT) - expectedCount); + reset = false; + } else { +- expectedBufferSize = (int) (observationCount.addAndGet(bufferActiveBit) - expectedCount); ++ expectedBufferSize = (int) (observationCount.addAndGet(BUFFER_ACTIVE_BIT) - expectedCount); + } + + appendLock.lock(); +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/CKMSQuantiles.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/CKMSQuantiles.java +@@ -21,6 +21,8 @@ See the License for the specific language governing permissions and + limitations under the License. + */ + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.Arrays; + import java.util.Iterator; + import java.util.LinkedList; +@@ -62,9 +64,7 @@ final class CKMSQuantiles { + private int bufferPos = 0; + + public CKMSQuantiles(Quantile... quantiles) { +- if (quantiles.length == 0) { +- throw new IllegalArgumentException("quantiles cannot be empty"); +- } ++ checkArgument(quantiles.length != 0, "quantiles cannot be empty"); + this.quantiles = quantiles; + } + +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/CallbackMetric.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/CallbackMetric.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.snapshots.Labels; + import java.util.List; +@@ -17,29 +19,22 @@ abstract class CallbackMetric extends MetricWithFixedMetadata { + + protected Labels makeLabels(String... labelValues) { + if (labelNames.length == 0) { +- if (labelValues != null && labelValues.length > 0) { +- throw new IllegalArgumentException( +- "Cannot pass label values to a " +- + this.getClass().getSimpleName() +- + " that was created without label names."); +- } ++ checkArgument( ++ labelValues == null || labelValues.length <= 0, ++ "Cannot pass label values to a %s that was created without label names.", ++ this.getClass().getSimpleName()); + return constLabels; + } else { +- if (labelValues == null) { +- throw new IllegalArgumentException( +- this.getClass().getSimpleName() +- + " was created with label names, " +- + "but the callback was called without label values."); +- } +- if (labelValues.length != labelNames.length) { +- throw new IllegalArgumentException( +- this.getClass().getSimpleName() +- + " was created with " +- + labelNames.length +- + " label names, but the callback was called with " +- + labelValues.length +- + " label values."); +- } ++ checkArgument( ++ labelValues != null, ++ "%s was created with label names, but the callback was called without label values.", ++ this.getClass().getSimpleName()); ++ checkArgument( ++ labelValues.length == labelNames.length, ++ "%s was created with %s label names, but the callback was called with %s label values.", ++ this.getClass().getSimpleName(), ++ labelNames.length, ++ labelValues.length); + return constLabels.merge(Labels.of(labelNames, labelValues)); + } + } +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Counter.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Counter.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.MetricsProperties; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.core.datapoints.CounterDataPoint; +@@ -9,7 +12,6 @@ import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import io.prometheus.metrics.model.snapshots.Exemplar; + import io.prometheus.metrics.model.snapshots.Labels; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.concurrent.atomic.DoubleAdder; + import java.util.concurrent.atomic.LongAdder; +@@ -169,18 +171,12 @@ public class Counter extends StatefulMetric + } + + private void validateAndAdd(long amount) { +- if (amount < 0) { +- throw new IllegalArgumentException( +- "Negative increment " + amount + " is illegal for Counter metrics."); +- } ++ checkArgument(amount >= 0, "Negative increment %s is illegal for Counter metrics.", amount); + longValue.add(amount); + } + + private void validateAndAdd(double amount) { +- if (amount < 0) { +- throw new IllegalArgumentException( +- "Negative increment " + amount + " is illegal for Counter metrics."); +- } ++ checkArgument(amount >= 0, "Negative increment %s is illegal for Counter metrics.", amount); + doubleValue.add(amount); + } + +@@ -213,7 +209,7 @@ public class Counter extends StatefulMetric + public static class Builder extends StatefulMetric.Builder { + + private Builder(PrometheusProperties properties) { +- super(Collections.emptyList(), properties); ++ super(ImmutableList.of(), properties); + } + + /** +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/CounterWithCallback.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/CounterWithCallback.java +@@ -1,9 +1,11 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.function.Consumer; + +@@ -32,9 +34,7 @@ public class CounterWithCallback extends CallbackMetric { + private CounterWithCallback(Builder builder) { + super(builder); + this.callback = builder.callback; +- if (callback == null) { +- throw new IllegalArgumentException("callback cannot be null"); +- } ++ checkArgument(callback != null, "callback cannot be null"); + } + + @Override +@@ -68,7 +68,7 @@ public class CounterWithCallback extends CallbackMetric { + } + + private Builder(PrometheusProperties properties) { +- super(Collections.emptyList(), properties); ++ super(ImmutableList.of(), properties); + } + + /** +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Gauge.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Gauge.java +@@ -1,5 +1,6 @@ + package io.prometheus.metrics.core.metrics; + ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.MetricsProperties; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.core.datapoints.GaugeDataPoint; +@@ -9,7 +10,6 @@ import io.prometheus.metrics.model.snapshots.Exemplar; + import io.prometheus.metrics.model.snapshots.GaugeSnapshot; + import io.prometheus.metrics.model.snapshots.Labels; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.concurrent.atomic.AtomicLong; + +@@ -184,7 +184,7 @@ public class Gauge extends StatefulMetric + public static class Builder extends StatefulMetric.Builder { + + private Builder(PrometheusProperties config) { +- super(Collections.emptyList(), config); ++ super(ImmutableList.of(), config); + } + + @Override +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/GaugeWithCallback.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/GaugeWithCallback.java +@@ -1,9 +1,11 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.snapshots.GaugeSnapshot; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.function.Consumer; + +@@ -37,9 +39,7 @@ public class GaugeWithCallback extends CallbackMetric { + private GaugeWithCallback(Builder builder) { + super(builder); + this.callback = builder.callback; +- if (callback == null) { +- throw new IllegalArgumentException("callback cannot be null"); +- } ++ checkArgument(callback != null, "callback cannot be null"); + } + + @Override +@@ -72,7 +72,7 @@ public class GaugeWithCallback extends CallbackMetric { + } + + private Builder(PrometheusProperties properties) { +- super(Collections.emptyList(), properties); ++ super(ImmutableList.of(), properties); + } + + @Override +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Histogram.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Histogram.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.ExemplarsProperties; + import io.prometheus.metrics.config.MetricsProperties; + import io.prometheus.metrics.config.PrometheusProperties; +@@ -14,7 +17,6 @@ import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.NativeHistogramBuckets; + import java.math.BigDecimal; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.Map; + import java.util.SortedSet; +@@ -372,8 +374,7 @@ public class Histogram extends StatefulMetric> -nativeSchema; +- return bucketIndex; ++ return (bucketIndex + offset) >> -nativeSchema; + } + } + +@@ -720,7 +721,7 @@ public class Histogram extends StatefulMetric + */ + public Builder nativeInitialSchema(int nativeSchema) { +- if (nativeSchema < -4 || nativeSchema > 8) { +- throw new IllegalArgumentException( +- "Unsupported native histogram schema " +- + nativeSchema +- + ": expecting -4 <= schema <= 8."); +- } ++ checkArgument( ++ nativeSchema >= -4 && nativeSchema <= 8, ++ "Unsupported native histogram schema %s: expecting -4 <= schema <= 8.", ++ nativeSchema); + this.nativeInitialSchema = nativeSchema; + return this; + } +@@ -888,10 +885,10 @@ public class Histogram extends StatefulMetricDefault is {@link Builder#DEFAULT_NATIVE_MAX_NUMBER_OF_BUCKETS}. + */ + public Builder nativeMaxZeroThreshold(double nativeMaxZeroThreshold) { +- if (nativeMaxZeroThreshold < 0) { +- throw new IllegalArgumentException( +- "Illegal native max zero threshold " + nativeMaxZeroThreshold + ": must be >= 0"); +- } ++ checkArgument( ++ nativeMaxZeroThreshold >= 0, ++ "Illegal native max zero threshold %s: must be >= 0", ++ nativeMaxZeroThreshold); + this.nativeMaxZeroThreshold = nativeMaxZeroThreshold; + return this; + } +@@ -907,10 +904,10 @@ public class Histogram extends StatefulMetricDefault is {@link Builder#DEFAULT_NATIVE_MIN_ZERO_THRESHOLD}. + */ + public Builder nativeMinZeroThreshold(double nativeMinZeroThreshold) { +- if (nativeMinZeroThreshold < 0) { +- throw new IllegalArgumentException( +- "Illegal native min zero threshold " + nativeMinZeroThreshold + ": must be >= 0"); +- } ++ checkArgument( ++ nativeMinZeroThreshold >= 0, ++ "Illegal native min zero threshold %s: must be >= 0", ++ nativeMinZeroThreshold); + this.nativeMinZeroThreshold = nativeMinZeroThreshold; + return this; + } +@@ -940,9 +937,7 @@ public class Histogram extends StatefulMetric 0 expected"); +- } ++ checkArgument(duration > 0, "%s: value > 0 expected", duration); + nativeResetDurationSeconds = unit.toSeconds(duration); + return this; + } +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Info.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Info.java +@@ -1,11 +1,13 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.snapshots.InfoSnapshot; + import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.Unit; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.Set; + import java.util.concurrent.CopyOnWriteArraySet; +@@ -42,51 +44,39 @@ public class Info extends MetricWithFixedMetadata { + * target_info} where you want only one single data point. + */ + public void setLabelValues(String... labelValues) { +- if (labelValues.length != labelNames.length) { +- throw new IllegalArgumentException( +- getClass().getSimpleName() +- + " " +- + getMetadata().getName() +- + " was created with " +- + labelNames.length +- + " label names, but you called setLabelValues() with " +- + labelValues.length +- + " label values."); +- } ++ checkArgument( ++ labelValues.length == labelNames.length, ++ "%s %s was created with %s label names, but you called setLabelValues() with %s label values.", ++ getClass().getSimpleName(), ++ getMetadata().getName(), ++ labelNames.length, ++ labelValues.length); + Labels newLabels = Labels.of(labelNames, labelValues); + labels.add(newLabels); +- labels.retainAll(Collections.singletonList(newLabels)); ++ labels.retainAll(ImmutableList.of(newLabels)); + } + + /** Create an info data point with the given label values. */ + public void addLabelValues(String... labelValues) { +- if (labelValues.length != labelNames.length) { +- throw new IllegalArgumentException( +- getClass().getSimpleName() +- + " " +- + getMetadata().getName() +- + " was created with " +- + labelNames.length +- + " label names, but you called addLabelValues() with " +- + labelValues.length +- + " label values."); +- } ++ checkArgument( ++ labelValues.length == labelNames.length, ++ "%s %s was created with %s label names, but you called addLabelValues() with %s label values.", ++ getClass().getSimpleName(), ++ getMetadata().getName(), ++ labelNames.length, ++ labelValues.length); + labels.add(Labels.of(labelNames, labelValues)); + } + + /** Remove the data point with the specified label values. */ + public void remove(String... labelValues) { +- if (labelValues.length != labelNames.length) { +- throw new IllegalArgumentException( +- getClass().getSimpleName() +- + " " +- + getMetadata().getName() +- + " was created with " +- + labelNames.length +- + " label names, but you called remove() with " +- + labelValues.length +- + " label values."); +- } ++ checkArgument( ++ labelValues.length == labelNames.length, ++ "%s %s was created with %s label names, but you called remove() with %s label values.", ++ getClass().getSimpleName(), ++ getMetadata().getName(), ++ labelNames.length, ++ labelValues.length); + Labels toBeRemoved = Labels.of(labelNames, labelValues); + labels.remove(toBeRemoved); + } +@@ -115,7 +105,7 @@ public class Info extends MetricWithFixedMetadata { + public static class Builder extends MetricWithFixedMetadata.Builder { + + private Builder(PrometheusProperties config) { +- super(Collections.emptyList(), config); ++ super(ImmutableList.of(), config); + } + + /** +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Metric.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Metric.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.registry.Collector; + import io.prometheus.metrics.model.registry.PrometheusRegistry; +@@ -40,10 +42,10 @@ public abstract class Metric implements Collector { + // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels + public B constLabels(Labels constLabels) { + for (Label label : constLabels) { // NPE if constLabels is null +- if (illegalLabelNames.contains(label.getName())) { +- throw new IllegalArgumentException( +- label.getName() + ": illegal label name for this metric type"); +- } ++ checkArgument( ++ !illegalLabelNames.contains(label.getName()), ++ "%s: illegal label name for this metric type", ++ label.getName()); + } + this.constLabels = constLabels; + return self(); +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/MetricWithFixedMetadata.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/MetricWithFixedMetadata.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.MetricMetadata; +@@ -58,9 +60,7 @@ public abstract class MetricWithFixedMetadata extends Metric { + + public B name(String name) { + String error = PrometheusNaming.validateMetricName(name); +- if (error != null) { +- throw new IllegalArgumentException("'" + name + "': Illegal metric name: " + error); +- } ++ checkArgument(error == null, "'%s': Illegal metric name: %s", name, error); + this.name = name; + return self(); + } +@@ -77,16 +77,13 @@ public abstract class MetricWithFixedMetadata extends Metric { + + public B labelNames(String... labelNames) { + for (String labelName : labelNames) { +- if (!PrometheusNaming.isValidLabelName(labelName)) { +- throw new IllegalArgumentException(labelName + ": illegal label name"); +- } +- if (illegalLabelNames.contains(labelName)) { +- throw new IllegalArgumentException( +- labelName + ": illegal label name for this metric type"); +- } +- if (constLabels.contains(labelName)) { +- throw new IllegalArgumentException(labelName + ": duplicate label name"); +- } ++ checkArgument( ++ PrometheusNaming.isValidLabelName(labelName), "%s: illegal label name", labelName); ++ checkArgument( ++ !illegalLabelNames.contains(labelName), ++ "%s: illegal label name for this metric type", ++ labelName); ++ checkArgument(!constLabels.contains(labelName), "%s: duplicate label name", labelName); + } + this.labelNames = labelNames; + return self(); +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/StateSet.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/StateSet.java +@@ -1,16 +1,18 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++import static com.google.common.base.Preconditions.checkState; + import static io.prometheus.metrics.model.snapshots.PrometheusNaming.prometheusName; + ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.MetricsProperties; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.core.datapoints.StateSetDataPoint; + import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.StateSetSnapshot; + import java.util.ArrayList; +-import java.util.Collections; ++import java.util.Arrays; + import java.util.List; +-import java.util.stream.Stream; + + /** + * StateSet metric. Example: +@@ -62,12 +64,10 @@ public class StateSet extends StatefulMetric> enumClass) { + return states( +- Stream.of(enumClass.getEnumConstants()).map(Enum::toString).toArray(String[]::new)); ++ Arrays.stream(enumClass.getEnumConstants()).map(Enum::toString).toArray(String[]::new)); + } + + /** Declare the states that should be represented by this StateSet. */ + public Builder states(String... stateNames) { +- if (stateNames.length == 0) { +- throw new IllegalArgumentException("states cannot be empty"); +- } +- this.names = Stream.of(stateNames).distinct().sorted().toArray(String[]::new); ++ checkArgument(stateNames.length != 0, "states cannot be empty"); ++ this.names = Arrays.stream(stateNames).distinct().sorted().toArray(String[]::new); + return this; + } + + @Override + public StateSet build() { +- if (names == null) { +- throw new IllegalStateException("State names are required when building a StateSet."); +- } ++ checkState(names != null, "State names are required when building a StateSet."); + return new StateSet(this, properties); + } + +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Summary.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/Summary.java +@@ -1,5 +1,9 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++import static java.util.Collections.unmodifiableList; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.MetricsProperties; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.core.datapoints.DistributionDataPoint; +@@ -11,7 +15,6 @@ import io.prometheus.metrics.model.snapshots.Quantile; + import io.prometheus.metrics.model.snapshots.Quantiles; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.concurrent.TimeUnit; + import java.util.concurrent.atomic.DoubleAdder; +@@ -51,7 +54,7 @@ public class Summary extends StatefulMetric 0) { ++ if (!quantileErrors.isEmpty()) { + result.add(new CKMSQuantiles.Quantile(quantiles.get(i), quantileErrors.get(i))); + } else { + result.add( +@@ -122,7 +125,7 @@ public class Summary extends StatefulMetric 0) { ++ if (!quantiles.isEmpty()) { + CKMSQuantiles.Quantile[] quantilesArray = quantiles.toArray(new CKMSQuantiles.Quantile[0]); + quantileValues = + new SlidingWindow<>( +@@ -228,7 +231,7 @@ public class Summary extends StatefulMetric + */ + public Builder quantile(double quantile, double error) { +- if (quantile < 0.0 || quantile > 1.0) { +- throw new IllegalArgumentException( +- "Quantile " + quantile + " invalid: Expected number between 0.0 and 1.0."); +- } +- if (error < 0.0 || error > 1.0) { +- throw new IllegalArgumentException( +- "Error " + error + " invalid: Expected number between 0.0 and 1.0."); +- } ++ checkArgument( ++ quantile >= 0.0 && quantile <= 1.0, ++ "Quantile %s invalid: Expected number between 0.0 and 1.0.", ++ quantile); ++ checkArgument( ++ error >= 0.0 && error <= 1.0, ++ "Error %s invalid: Expected number between 0.0 and 1.0.", ++ error); + quantiles.add(new CKMSQuantiles.Quantile(quantile, error)); + return this; + } +@@ -293,9 +296,7 @@ public class Summary extends StatefulMetric 0, "maxAgeSeconds cannot be %s", maxAgeSeconds); + this.maxAgeSeconds = maxAgeSeconds; + return this; + } +@@ -307,9 +308,7 @@ public class Summary extends StatefulMetric 0, "ageBuckets cannot be %s", ageBuckets); + this.ageBuckets = ageBuckets; + return this; + } +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/SummaryWithCallback.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/SummaryWithCallback.java +@@ -1,11 +1,13 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.snapshots.Exemplars; + import io.prometheus.metrics.model.snapshots.Quantiles; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; + import java.util.ArrayList; +-import java.util.Collections; + import java.util.List; + import java.util.function.Consumer; + +@@ -45,9 +47,7 @@ public class SummaryWithCallback extends CallbackMetric { + private SummaryWithCallback(Builder builder) { + super(builder); + this.callback = builder.callback; +- if (callback == null) { +- throw new IllegalArgumentException("callback cannot be null"); +- } ++ checkArgument(callback != null, "callback cannot be null"); + } + + @Override +@@ -81,7 +81,7 @@ public class SummaryWithCallback extends CallbackMetric { + } + + private Builder(PrometheusProperties properties) { +- super(Collections.singletonList("quantile"), properties); ++ super(ImmutableList.of("quantile"), properties); + } + + @Override +--- a/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/util/Scheduler.java ++++ b/prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/util/Scheduler.java +@@ -22,11 +22,11 @@ public class Scheduler { + } + } + +- private static final ScheduledExecutorService executor = ++ private static final ScheduledExecutorService EXECUTOR = + Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory()); + + public static ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { +- return executor.schedule(command, delay, unit); ++ return EXECUTOR.schedule(command, delay, unit); + } + + /** For unit test. Wait until the executor Thread is running. */ +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/datapoints/CounterDataPointTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/datapoints/CounterDataPointTest.java +@@ -5,7 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat; + import io.prometheus.metrics.model.snapshots.Labels; + import org.junit.jupiter.api.Test; + +-class CounterDataPointTest { ++final class CounterDataPointTest { + + private double value = 0; + +@@ -32,7 +32,7 @@ class CounterDataPointTest { + } + }; + counterDataPoint.inc(1); +- assertThat(value).isOne(); ++ assertThat(value).isEqualTo(1); + counterDataPoint.incWithExemplar(1, null); + assertThat(value).isEqualTo(2); + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/datapoints/TimerApiTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/datapoints/TimerApiTest.java +@@ -4,7 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; + + import org.junit.jupiter.api.Test; + +-class TimerApiTest { ++final class TimerApiTest { + + private double time = 0; + +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/exemplars/ExemplarSamplerTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/exemplars/ExemplarSamplerTest.java +@@ -11,7 +11,7 @@ import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class ExemplarSamplerTest { ++final class ExemplarSamplerTest { + + private final int tick = 10; // Time step in milliseconds. Make this larger if the test is flaky. + private final int sampleInterval = 10 * tick; // do not change this +@@ -52,24 +52,24 @@ class ExemplarSamplerTest { + } + + @Test +- public void testCustomExemplarsBuckets() throws Exception { ++ void customExemplarsBuckets() throws Exception { + // TODO + } + + private io.prometheus.metrics.tracer.common.SpanContext origContext; + + @BeforeEach +- public void setUp() { ++ void setUp() { + origContext = SpanContextSupplier.getSpanContext(); + } + + @AfterEach +- public void tearDown() { ++ void tearDown() { + SpanContextSupplier.setSpanContext(origContext); + } + + @Test +- public void testIsSampled() throws Exception { ++ void isSampled() throws Exception { + SpanContext context = new SpanContext(); + context.isSampled = false; + ExemplarSampler sampler = new ExemplarSampler(makeConfig(), context); +@@ -79,7 +79,7 @@ class ExemplarSamplerTest { + } + + @Test +- public void testDefaultConfigHasFourExemplars() throws Exception { ++ void defaultConfigHasFourExemplars() throws Exception { + ExemplarSampler sampler = new ExemplarSampler(makeConfig(), new SpanContext()); + Thread.sleep(tick); // t = 1 tick + sampler.observe(0.3); +@@ -96,7 +96,7 @@ class ExemplarSamplerTest { + } + + @Test +- public void testEmptyBuckets() throws Exception { ++ void emptyBuckets() throws Exception { + ExemplarSampler sampler = + new ExemplarSampler(makeConfig(Double.POSITIVE_INFINITY), new SpanContext()); + Thread.sleep(tick); // t = 1 tick +@@ -108,7 +108,7 @@ class ExemplarSamplerTest { + } + + @Test +- public void testDefaultExemplarsBuckets() throws Exception { ++ void defaultExemplarsBuckets() throws Exception { + ExemplarSampler sampler = + new ExemplarSampler( + makeConfig(0.2, 0.4, 0.6, 0.8, 1.0, Double.POSITIVE_INFINITY), new SpanContext()); +@@ -136,12 +136,12 @@ class ExemplarSamplerTest { + } + + @Test +- public void testCustomExemplarsNoBuckets() throws Exception { ++ void customExemplarsNoBuckets() throws Exception { + // TODO + } + + @Test +- public void testDefaultExemplarsNoBuckets() throws Exception { ++ void defaultExemplarsNoBuckets() throws Exception { + ExemplarSampler sampler = new ExemplarSampler(makeConfig(), new SpanContext()); + Scheduler.awaitInitialization(); + Thread.sleep(tick); // t = 1 tick +@@ -192,7 +192,7 @@ class ExemplarSamplerTest { + break; + } + } +- assertThat(found).as(value + " not found").isTrue(); ++ assertThat(found).as("%s not found", value).isTrue(); + } + } + +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/exemplars/SpanContextSupplierTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/exemplars/SpanContextSupplierTest.java +@@ -12,7 +12,7 @@ import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class SpanContextSupplierTest { ++final class SpanContextSupplierTest { + + public SpanContext makeSpanContext(String traceId, String spanId) { + +@@ -51,12 +51,12 @@ class SpanContextSupplierTest { + ); + + @BeforeEach +- public void setUp() { ++ void setUp() { + origSpanContext = SpanContextSupplier.getSpanContext(); + } + + @AfterEach +- public void tearDown() { ++ void tearDown() { + SpanContextSupplier.setSpanContext(origSpanContext); + } + +@@ -66,7 +66,7 @@ class SpanContextSupplierTest { + * SpanContextSupplier}. + */ + @Test +- public void testConstructorInjection() { ++ void constructorInjection() { + ExemplarsProperties properties = ExemplarsProperties.builder().build(); + ExemplarSamplerConfig config = new ExemplarSamplerConfig(properties, 1); + ExemplarSampler exemplarSampler = new ExemplarSampler(config, spanContextA); +@@ -74,7 +74,7 @@ class SpanContextSupplierTest { + SpanContextSupplier.setSpanContext(spanContextB); + exemplarSampler.observe(1.0); + Exemplars exemplars = exemplarSampler.collect(); +- assertThat(exemplars.size()).isOne(); ++ assertThat(exemplars.size()).isEqualTo(1); + Exemplar exemplar = exemplars.get(0); + assertThat(exemplar.getLabels().get(TRACE_ID)).isEqualTo("A"); + } +@@ -86,13 +86,13 @@ class SpanContextSupplierTest { + * ExemplarSampler}). + */ + @Test +- public void testUpdateSpanContext() throws InterruptedException { ++ void updateSpanContext() throws InterruptedException { + ExemplarSampler exemplarSampler = new ExemplarSampler(config); + + SpanContextSupplier.setSpanContext(spanContextB); + exemplarSampler.observe(1.0); + Exemplars exemplars = exemplarSampler.collect(); +- assertThat(exemplars.size()).isOne(); ++ assertThat(exemplars.size()).isEqualTo(1); + Exemplar exemplar = exemplars.get(0); + assertThat(exemplar.getLabels().get(TRACE_ID)).isEqualTo("B"); + +@@ -101,7 +101,7 @@ class SpanContextSupplierTest { + SpanContextSupplier.setSpanContext(spanContextA); + exemplarSampler.observe(1.0); + exemplars = exemplarSampler.collect(); +- assertThat(exemplars.size()).isOne(); ++ assertThat(exemplars.size()).isEqualTo(1); + exemplar = exemplars.get(0); + assertThat(exemplar.getLabels().get(TRACE_ID)).isEqualTo("A"); + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CKMSQuantilesTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CKMSQuantilesTest.java +@@ -11,7 +11,7 @@ import org.apache.commons.math3.random.JDKRandomGenerator; + import org.apache.commons.math3.random.RandomGenerator; + import org.junit.jupiter.api.Test; + +-class CKMSQuantilesTest { ++final class CKMSQuantilesTest { + + private final Quantile qMin = new Quantile(0.0, 0.00); + private final Quantile q50 = new Quantile(0.5, 0.01); +@@ -20,13 +20,13 @@ class CKMSQuantilesTest { + private final Quantile qMax = new Quantile(1.0, 0.00); + + @Test +- public void testGetOnEmptyValues() { ++ void getOnEmptyValues() { + CKMSQuantiles ckms = new CKMSQuantiles(q50, q95, q99); + assertThat(Double.isNaN(ckms.get(q95.quantile))).isTrue(); + } + + @Test +- public void testGet() { ++ void get() { + Random random = new Random(0); + CKMSQuantiles ckms = new CKMSQuantiles(q50, q95, q99); + List input = shuffledValues(100, random); +@@ -37,7 +37,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testBatchInsert() { ++ void batchInsert() { + Random random = new Random(1); + testInsertBatch(1, 1, 100, random); + testInsertBatch(1, 10, 100, random); +@@ -87,7 +87,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testGetWithAMillionElements() { ++ void getWithAMillionElements() { + Random random = new Random(2); + List input = shuffledValues(1000 * 1000, random); + CKMSQuantiles ckms = new CKMSQuantiles(q50, q95, q99); +@@ -99,7 +99,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMin() { ++ void min() { + Random random = new Random(3); + List input = shuffledValues(1000, random); + CKMSQuantiles ckms = new CKMSQuantiles(qMin); +@@ -112,7 +112,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMax() { ++ void max() { + Random random = new Random(4); + List input = shuffledValues(1000, random); + CKMSQuantiles ckms = new CKMSQuantiles(qMax); +@@ -125,7 +125,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMinMax() { ++ void minMax() { + Random random = new Random(5); + List input = shuffledValues(1000, random); + CKMSQuantiles ckms = new CKMSQuantiles(qMin, qMax); +@@ -138,7 +138,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMinAndOthers() { ++ void minAndOthers() { + Random random = new Random(6); + List input = shuffledValues(1000, random); + CKMSQuantiles ckms = new CKMSQuantiles(q95, qMin); +@@ -150,7 +150,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMaxAndOthers() { ++ void maxAndOthers() { + Random random = new Random(7); + List input = shuffledValues(10000, random); + CKMSQuantiles ckms = new CKMSQuantiles(q50, q95, qMax); +@@ -162,7 +162,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMinMaxAndOthers() { ++ void minMaxAndOthers() { + Random random = new Random(8); + List input = shuffledValues(10000, random); + CKMSQuantiles ckms = new CKMSQuantiles(qMin, q50, q95, q99, qMax); +@@ -174,7 +174,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testExactQuantile() { ++ void exactQuantile() { + Random random = new Random(9); + List input = shuffledValues(10000, random); + CKMSQuantiles ckms = new CKMSQuantiles(new Quantile(0.95, 0)); +@@ -187,7 +187,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testExactAndOthers() { ++ void exactAndOthers() { + Random random = new Random(10); + List input = shuffledValues(10000, random); + CKMSQuantiles ckms = new CKMSQuantiles(q50, new Quantile(0.95, 0), q99); +@@ -200,7 +200,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testExactAndMin() { ++ void exactAndMin() { + Random random = new Random(11); + List input = shuffledValues(10000, random); + CKMSQuantiles ckms = new CKMSQuantiles(qMin, q50, new Quantile(0.95, 0)); +@@ -213,7 +213,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testMaxEpsilon() { ++ void maxEpsilon() { + Random random = new Random(12); + List input = shuffledValues(10000, random); + // epsilon == 1 basically gives you random results, but it should still not throw an exception. +@@ -225,7 +225,7 @@ class CKMSQuantilesTest { + } + + @Test +- public void testGetGaussian() { ++ void getGaussian() { + RandomGenerator rand = new JDKRandomGenerator(); + rand.setSeed(0); + +@@ -284,20 +284,20 @@ class CKMSQuantilesTest { + } + + @Test +- public void testIllegalArgumentException() { ++ void illegalArgumentException() { + try { + new Quantile(-1, 0); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).isEqualTo("Quantile must be between 0 and 1"); + } catch (Exception e) { +- fail("Wrong exception thrown" + e); ++ fail("Wrong exception thrown%s", e); + } + try { + new Quantile(0.95, 2); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).isEqualTo("Epsilon must be between 0 and 1"); + } catch (Exception e) { +- fail("Wrong exception thrown" + e); ++ fail("Wrong exception thrown%s", e); + } + } + +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CallbackMetricTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CallbackMetricTest.java +@@ -1,15 +1,14 @@ + package io.prometheus.metrics.core.metrics; + +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import org.junit.jupiter.api.Test; + +-class CallbackMetricTest { ++final class CallbackMetricTest { + + @Test + void makeLabels() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + CounterWithCallback.builder() + .name("c") +@@ -17,11 +16,11 @@ class CallbackMetricTest { + .labelNames("label1", "label2") + .build() + .makeLabels("foo")) +- .withMessage( ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "CounterWithCallback was created with 2 label names, but the callback was called with 1 label values."); + +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + CounterWithCallback.builder() + .name("c") +@@ -29,18 +28,19 @@ class CallbackMetricTest { + .labelNames("label1", "label2") + .build() + .makeLabels((String[]) null)) +- .withMessage( ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "CounterWithCallback was created with label names, but the callback was called without label values."); + +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + CounterWithCallback.builder() + .name("c") + .callback(callback -> {}) + .build() + .makeLabels("foo")) +- .withMessage( ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "Cannot pass label values to a CounterWithCallback that was created without label names."); + } + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CounterTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CounterTest.java +@@ -2,7 +2,7 @@ package io.prometheus.metrics.core.metrics; + + import static io.prometheus.metrics.core.metrics.TestUtil.assertExemplarEquals; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.assertj.core.data.Offset.offset; + + import io.prometheus.metrics.core.exemplars.ExemplarSamplerConfigTestUtil; +@@ -22,28 +22,29 @@ import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class CounterTest { ++final class CounterTest { + + private Counter noLabels; + private Counter labels; +- private static final long exemplarSampleIntervalMillis = 10; +- private static final long exemplarMinAgeMillis = 100; ++ private static final long EXEMPLAR_SAMPLE_INTERVAL_MILLIS = 10; ++ private static final long EXEMPLAR_MIN_AGE_MILLIS = 100; + private SpanContext origSpanContext; + + @BeforeEach +- public void setUp() throws NoSuchFieldException, IllegalAccessException { ++ void setUp() throws NoSuchFieldException, IllegalAccessException { + noLabels = Counter.builder().name("nolabels").build(); + labels = + Counter.builder().name("labels").help("help").unit(Unit.SECONDS).labelNames("l").build(); + origSpanContext = SpanContextSupplier.getSpanContext(); +- ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(noLabels, exemplarSampleIntervalMillis); +- ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(noLabels, exemplarMinAgeMillis); +- ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(labels, exemplarSampleIntervalMillis); +- ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(labels, exemplarMinAgeMillis); ++ ExemplarSamplerConfigTestUtil.setSampleIntervalMillis( ++ noLabels, EXEMPLAR_SAMPLE_INTERVAL_MILLIS); ++ ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(noLabels, EXEMPLAR_MIN_AGE_MILLIS); ++ ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(labels, EXEMPLAR_SAMPLE_INTERVAL_MILLIS); ++ ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(labels, EXEMPLAR_MIN_AGE_MILLIS); + } + + @AfterEach +- public void tearDown() { ++ void tearDown() { + SpanContextSupplier.setSpanContext(origSpanContext); + } + +@@ -66,7 +67,7 @@ class CounterTest { + } + + @Test +- public void testIncrement() { ++ void increment() { + noLabels.inc(); + assertThat(getValue(noLabels)).isCloseTo(1.0, offset(.001)); + noLabels.inc(2); +@@ -78,23 +79,23 @@ class CounterTest { + } + + @Test +- public void testNegativeIncrementFails() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> noLabels.inc(-1)) +- .withMessage("Negative increment -1 is illegal for Counter metrics."); ++ void negativeIncrementFails() { ++ assertThatThrownBy(() -> noLabels.inc(-1)) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage("Negative increment -1 is illegal for Counter metrics."); + } + + @Test +- public void testEmptyCountersHaveNoLabels() { +- assertThat(getNumberOfLabels(noLabels)).isOne(); +- assertThat(getNumberOfLabels(labels)).isZero(); ++ void emptyCountersHaveNoLabels() { ++ assertThat(getNumberOfLabels(noLabels)).isEqualTo(1); ++ assertThat(getNumberOfLabels(labels)).isEqualTo(0); + } + + @Test +- public void testLabels() { +- assertThat(getNumberOfLabels(labels)).isZero(); ++ void labels() { ++ assertThat(getNumberOfLabels(labels)).isEqualTo(0); + labels.labelValues("a").inc(); +- assertThat(getNumberOfLabels(labels)).isOne(); ++ assertThat(getNumberOfLabels(labels)).isEqualTo(1); + assertThat(getValue(labels, "l", "a")).isCloseTo(1.0, offset(.001)); + labels.labelValues("b").inc(3); + assertThat(getNumberOfLabels(labels)).isEqualTo(2); +@@ -103,7 +104,7 @@ class CounterTest { + } + + @Test +- public void testTotalStrippedFromName() { ++ void totalStrippedFromName() { + for (String name : + new String[] { + "my_counter_total", "my.counter.total", +@@ -121,7 +122,7 @@ class CounterTest { + } + + @Test +- public void testSnapshotComplete() { ++ void snapshotComplete() { + long before = System.currentTimeMillis(); + Counter counter = + Counter.builder() +@@ -176,16 +177,16 @@ class CounterTest { + } + + @Test +- public void testIncWithExemplar() throws Exception { ++ void testIncWithExemplar() throws Exception { + noLabels.incWithExemplar(Labels.of("key", "value")); + assertExemplar(noLabels, 1.0, "key", "value"); + +- Thread.sleep(exemplarMinAgeMillis + 2 * exemplarSampleIntervalMillis); ++ Thread.sleep(EXEMPLAR_MIN_AGE_MILLIS + 2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + noLabels.incWithExemplar(Labels.EMPTY); + assertExemplar(noLabels, 1.0); + +- Thread.sleep(exemplarMinAgeMillis + 2 * exemplarSampleIntervalMillis); ++ Thread.sleep(EXEMPLAR_MIN_AGE_MILLIS + 2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + noLabels.incWithExemplar(3, Labels.of("key1", "value1", "key2", "value2")); + assertExemplar(noLabels, 3, "key1", "value1", "key2", "value2"); +@@ -198,7 +199,7 @@ class CounterTest { + } + + @Test +- public void testExemplarSampler() throws Exception { ++ void exemplarSampler() throws Exception { + Exemplar exemplar1 = Exemplar.builder().value(2.0).traceId("abc").spanId("123").build(); + Exemplar exemplar2 = Exemplar.builder().value(1.0).traceId("def").spanId("456").build(); + Exemplar exemplar3 = Exemplar.builder().value(1.0).traceId("123").spanId("abc").build(); +@@ -258,34 +259,34 @@ class CounterTest { + Counter counter = Counter.builder().name("count_total").build(); + + SpanContextSupplier.setSpanContext(spanContext); +- ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(counter, exemplarMinAgeMillis); +- ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(counter, exemplarSampleIntervalMillis); ++ ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(counter, EXEMPLAR_MIN_AGE_MILLIS); ++ ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(counter, EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + counter.inc(2.0); + assertExemplarEquals(exemplar1, getData(counter).getExemplar()); + +- Thread.sleep(2 * exemplarSampleIntervalMillis); ++ Thread.sleep(2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + counter.inc( + 3.0); // min age not reached -> keep the previous exemplar, exemplar sampler not called + assertExemplarEquals(exemplar1, getData(counter).getExemplar()); + +- Thread.sleep(exemplarMinAgeMillis + 2 * exemplarSampleIntervalMillis); ++ Thread.sleep(EXEMPLAR_MIN_AGE_MILLIS + 2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + counter.inc(2.0); // 2nd call: isSampled() returns false -> not sampled + assertExemplarEquals(exemplar1, getData(counter).getExemplar()); + +- Thread.sleep(2 * exemplarSampleIntervalMillis); ++ Thread.sleep(2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + counter.inc(1.0); // sampled + assertExemplarEquals(exemplar2, getData(counter).getExemplar()); + +- Thread.sleep(exemplarMinAgeMillis + 2 * exemplarSampleIntervalMillis); ++ Thread.sleep(EXEMPLAR_MIN_AGE_MILLIS + 2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + counter.inc(1.0); // sampled + assertExemplarEquals(exemplar3, getData(counter).getExemplar()); + +- Thread.sleep(2 * exemplarSampleIntervalMillis); ++ Thread.sleep(2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + counter.incWithExemplar( + Labels.of( +@@ -326,7 +327,7 @@ class CounterTest { + } + + @Test +- public void testExemplarSamplerDisabled() { ++ void exemplarSamplerDisabled() { + Counter counter = + Counter.builder() + // .withExemplarSampler((inc, prev) -> {throw new RuntimeException("unexpected call to +@@ -341,26 +342,26 @@ class CounterTest { + } + + @Test +- public void testConstLabelsFirst() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( ++ void constLabelsFirst() { ++ assertThatThrownBy( + () -> + Counter.builder() + .name("test_total") + .constLabels(Labels.of("const_a", "const_b")) + .labelNames("const.a") +- .build()); ++ .build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testConstLabelsSecond() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( ++ void constLabelsSecond() { ++ assertThatThrownBy( + () -> + Counter.builder() + .name("test_total") + .labelNames("const.a") + .constLabels(Labels.of("const_a", "const_b")) +- .build()); ++ .build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CounterWithCallbackTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CounterWithCallbackTest.java +@@ -1,7 +1,7 @@ + package io.prometheus.metrics.core.metrics; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.assertj.core.data.Offset.offset; + + import io.prometheus.metrics.model.snapshots.CounterSnapshot; +@@ -10,10 +10,10 @@ import java.util.List; + import java.util.concurrent.atomic.AtomicInteger; + import org.junit.jupiter.api.Test; + +-class CounterWithCallbackTest { ++final class CounterWithCallbackTest { + + @Test +- public void testCounter() { ++ void counter() { + final AtomicInteger value = new AtomicInteger(1); + List labelValues = Arrays.asList("v1", "v2"); + CounterWithCallback counter = +@@ -25,22 +25,22 @@ class CounterWithCallbackTest { + .build(); + CounterSnapshot snapshot = counter.collect(); + +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + CounterSnapshot.CounterDataPointSnapshot datapoint = snapshot.getDataPoints().get(0); + assertThat(datapoint.getValue()).isCloseTo(value.doubleValue(), offset(0.1)); + assertThat(datapoint.getLabels().size()).isEqualTo(labelValues.size()); + + value.incrementAndGet(); + snapshot = counter.collect(); +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + datapoint = snapshot.getDataPoints().get(0); + assertThat(datapoint.getValue()).isCloseTo(value.doubleValue(), offset(0.1)); + } + + @Test +- public void testCounterNoCallback() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( +- () -> CounterWithCallback.builder().name("counter").labelNames("l1", "l2").build()); ++ void counterNoCallback() { ++ assertThatThrownBy( ++ () -> CounterWithCallback.builder().name("counter").labelNames("l1", "l2").build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/GaugeTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/GaugeTest.java +@@ -15,24 +15,24 @@ import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class GaugeTest { ++final class GaugeTest { + +- private static final long exemplarSampleIntervalMillis = 10; +- private static final long exemplarMinAgeMillis = 100; ++ private static final long EXEMPLAR_SAMPLE_INTERVAL_MILLIS = 10; ++ private static final long EXEMPLAR_MIN_AGE_MILLIS = 100; + + private Gauge noLabels, labels; + + private SpanContext origSpanContext; + + @BeforeEach +- public void setUp() { ++ void setUp() { + noLabels = Gauge.builder().name("nolabels").build(); + labels = Gauge.builder().name("labels").labelNames("l").build(); + origSpanContext = SpanContextSupplier.getSpanContext(); + } + + @AfterEach +- public void tearDown() { ++ void tearDown() { + SpanContextSupplier.setSpanContext(origSpanContext); + } + +@@ -48,7 +48,7 @@ class GaugeTest { + } + + @Test +- public void testIncrement() { ++ void increment() { + noLabels.inc(); + assertThat(getValue(noLabels)).isCloseTo(1.0, offset(.001)); + noLabels.inc(2); +@@ -60,7 +60,7 @@ class GaugeTest { + } + + @Test +- public void testDecrement() { ++ void decrement() { + noLabels.dec(); + assertThat(getValue(noLabels)).isCloseTo(-1.0, offset(.001)); + noLabels.dec(2); +@@ -72,16 +72,16 @@ class GaugeTest { + } + + @Test +- public void testSet() { ++ void set() { + noLabels.set(42); + assertThat(getValue(noLabels)).isCloseTo(42, offset(.001)); + noLabels.set(7); + assertThat(getValue(noLabels)).isCloseTo(7.0, offset(.001)); + } + +- @Test + @SuppressWarnings("try") +- public void testTimer() throws InterruptedException { ++ @Test ++ void timer() throws InterruptedException { + try (Timer ignored = noLabels.startTimer()) { + Thread.sleep(12); + } +@@ -90,12 +90,12 @@ class GaugeTest { + } + + @Test +- public void noLabelsDefaultZeroValue() { ++ void noLabelsDefaultZeroValue() { + assertThat(getValue(noLabels)).isCloseTo(0.0, offset(.001)); + } + + @Test +- public void testLabels() { ++ void labels() { + labels.labelValues("a").inc(); + labels.labelValues("b").inc(3); + assertThat(getValue(labels, "l", "a")).isCloseTo(1.0, offset(.001)); +@@ -103,7 +103,7 @@ class GaugeTest { + } + + @Test +- public void testExemplarSampler() throws Exception { ++ void exemplarSampler() throws Exception { + Exemplar exemplar1 = Exemplar.builder().value(2.0).traceId("abc").spanId("123").build(); + Exemplar exemplar2 = Exemplar.builder().value(6.5).traceId("def").spanId("456").build(); + Exemplar exemplar3 = Exemplar.builder().value(7.0).traceId("123").spanId("abc").build(); +@@ -161,35 +161,35 @@ class GaugeTest { + }; + Gauge gauge = Gauge.builder().name("my_gauge").build(); + +- ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(gauge, exemplarMinAgeMillis); +- ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(gauge, exemplarSampleIntervalMillis); ++ ExemplarSamplerConfigTestUtil.setMinRetentionPeriodMillis(gauge, EXEMPLAR_MIN_AGE_MILLIS); ++ ExemplarSamplerConfigTestUtil.setSampleIntervalMillis(gauge, EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + SpanContextSupplier.setSpanContext(spanContext); + + gauge.inc(2.0); + assertExemplarEquals(exemplar1, getData(gauge).getExemplar()); + +- Thread.sleep(2 * exemplarSampleIntervalMillis); ++ Thread.sleep(2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + gauge.inc( + 3.0); // min age not reached -> keep the previous exemplar, exemplar sampler not called + assertExemplarEquals(exemplar1, getData(gauge).getExemplar()); + +- Thread.sleep(exemplarMinAgeMillis + 2 * exemplarSampleIntervalMillis); ++ Thread.sleep(EXEMPLAR_MIN_AGE_MILLIS + 2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + gauge.inc(2.0); // 2nd call: isSampled() returns false -> not sampled + assertExemplarEquals(exemplar1, getData(gauge).getExemplar()); + +- Thread.sleep(2 * exemplarSampleIntervalMillis); ++ Thread.sleep(2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + gauge.dec(0.5); // sampled + assertExemplarEquals(exemplar2, getData(gauge).getExemplar()); + +- Thread.sleep(exemplarMinAgeMillis + 2 * exemplarSampleIntervalMillis); ++ Thread.sleep(EXEMPLAR_MIN_AGE_MILLIS + 2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + gauge.set(7.0); // sampled + assertExemplarEquals(exemplar3, getData(gauge).getExemplar()); + +- Thread.sleep(2 * exemplarSampleIntervalMillis); ++ Thread.sleep(2 * EXEMPLAR_SAMPLE_INTERVAL_MILLIS); + + gauge.incWithExemplar( + Labels.of( +@@ -230,7 +230,7 @@ class GaugeTest { + } + + @Test +- public void testExemplarSamplerDisabled() { ++ void exemplarSamplerDisabled() { + Gauge gauge = Gauge.builder().name("test").withoutExemplars().build(); + gauge.setWithExemplar(3.0, Labels.of("a", "b")); + assertThat(getData(gauge).getExemplar()).isNull(); +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/GaugeWithCallbackTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/GaugeWithCallbackTest.java +@@ -1,7 +1,7 @@ + package io.prometheus.metrics.core.metrics; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.assertj.core.data.Offset.offset; + + import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +@@ -10,10 +10,10 @@ import java.util.List; + import java.util.concurrent.atomic.AtomicInteger; + import org.junit.jupiter.api.Test; + +-class GaugeWithCallbackTest { ++final class GaugeWithCallbackTest { + + @Test +- public void testGauge() { ++ void gauge() { + final AtomicInteger value = new AtomicInteger(1); + List labelValues = Arrays.asList("v1", "v2"); + GaugeWithCallback gauge = +@@ -25,21 +25,22 @@ class GaugeWithCallbackTest { + .build(); + GaugeSnapshot snapshot = gauge.collect(); + +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + GaugeSnapshot.GaugeDataPointSnapshot datapoint = snapshot.getDataPoints().get(0); + assertThat(datapoint.getValue()).isCloseTo(value.doubleValue(), offset(0.1)); + assertThat(datapoint.getLabels().size()).isEqualTo(labelValues.size()); + + value.incrementAndGet(); + snapshot = gauge.collect(); +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + datapoint = snapshot.getDataPoints().get(0); + assertThat(datapoint.getValue()).isCloseTo(value.doubleValue(), offset(0.1)); + } + + @Test +- public void testGaugeNoCallback() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> GaugeWithCallback.builder().name("gauge").labelNames("l1", "l2").build()); ++ void gaugeNoCallback() { ++ assertThatThrownBy( ++ () -> GaugeWithCallback.builder().name("gauge").labelNames("l1", "l2").build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java +@@ -1,8 +1,10 @@ + package io.prometheus.metrics.core.metrics; + ++import static com.google.common.collect.ImmutableList.toImmutableList; + import static io.prometheus.metrics.core.metrics.TestUtil.assertExemplarEquals; ++import static java.util.Comparator.comparingDouble; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.assertj.core.data.Offset.offset; + + import io.prometheus.metrics.core.datapoints.DistributionDataPoint; +@@ -26,8 +28,6 @@ import java.lang.reflect.InvocationTargetException; + import java.lang.reflect.Method; + import java.util.ArrayList; + import java.util.Arrays; +-import java.util.Collections; +-import java.util.Comparator; + import java.util.List; + import java.util.Random; + import java.util.concurrent.CompletionService; +@@ -39,12 +39,11 @@ import java.util.concurrent.Executors; + import java.util.concurrent.Future; + import java.util.concurrent.TimeUnit; + import java.util.concurrent.TimeoutException; +-import java.util.stream.Collectors; + import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class HistogramTest { ++final class HistogramTest { + + private static final double RESET_DURATION_REACHED = + -123.456; // just a random value indicating that we should simulate that the reset duration +@@ -53,12 +52,12 @@ class HistogramTest { + private SpanContext origSpanContext; + + @BeforeEach +- public void setUp() { ++ void setUp() { + origSpanContext = SpanContextSupplier.getSpanContext(); + } + + @AfterEach +- public void tearDown() { ++ void tearDown() { + SpanContextSupplier.setSpanContext(origSpanContext); + } + +@@ -93,14 +92,14 @@ class HistogramTest { + String expectedWithMetadata = + "name: \"test\" type: HISTOGRAM metric { histogram { " + expected + " } }"; + assertThat(ProtobufUtil.shortDebugString(protobufData)) +- .as("test \"" + name + "\" failed") ++ .as("test \"%s\" failed", name) + .isEqualTo(expectedWithMetadata); + } + } + + /** Test cases copied from histogram_test.go in client_golang. */ + @Test +- public void testGolangTests() throws NoSuchFieldException, IllegalAccessException { ++ void golangTests() throws NoSuchFieldException, IllegalAccessException { + GolangTestCase[] testCases = + new GolangTestCase[] { + new GolangTestCase( +@@ -762,7 +761,7 @@ class HistogramTest { + + /** Additional tests that are not part of client_golang's test suite. */ + @Test +- public void testAdditional() throws NoSuchFieldException, IllegalAccessException { ++ void additional() throws NoSuchFieldException, IllegalAccessException { + GolangTestCase[] testCases = + new GolangTestCase[] { + new GolangTestCase( +@@ -796,7 +795,7 @@ class HistogramTest { + *

This test is ported from client_golang's TestGetLe(). + */ + @Test +- public void testNativeBucketIndexToUpperBound() ++ void nativeBucketIndexToUpperBound() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + int[] indexes = new int[] {-1, 0, 1, 512, 513, -1, 0, 1, 1024, 1025, -1, 0, 1, 4096, 4097}; + int[] schemas = new int[] {-1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2}; +@@ -828,7 +827,7 @@ class HistogramTest { + Histogram.DataPoint histogramData = histogram.newDataPoint(); + double result = (double) method.invoke(histogramData, schemas[i], indexes[i]); + assertThat(result) +- .as("index=" + indexes[i] + ", schema=" + schemas[i]) ++ .as("index=%s, schema=%s", indexes[i], schemas[i]) + .isCloseTo(expectedUpperBounds[i], offset(0.0000000000001)); + } + } +@@ -838,7 +837,7 @@ class HistogramTest { + * findBucketIndex() + */ + @Test +- public void testFindBucketIndex() ++ void findBucketIndex() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Random rand = new Random(); + Method findBucketIndex = +@@ -865,17 +864,8 @@ class HistogramTest { + histogram.getNoLabels(), schema, bucketIndex); + assertThat(lowerBound < value && upperBound >= value) + .as( +- "Bucket index " +- + bucketIndex +- + " with schema " +- + schema +- + " has range [" +- + lowerBound +- + ", " +- + upperBound +- + "]. Value " +- + value +- + " is outside of that range.") ++ "Bucket index %s with schema %s has range [%s, %s]. Value %s is outside of that range.", ++ bucketIndex, schema, lowerBound, upperBound, value) + .isTrue(); + } + } +@@ -883,7 +873,7 @@ class HistogramTest { + } + + @Test +- public void testDefaults() throws IOException { ++ void defaults() throws IOException { + Histogram histogram = Histogram.builder().name("test").build(); + histogram.observe(0.5); + HistogramSnapshot snapshot = histogram.collect(); +@@ -951,7 +941,7 @@ class HistogramTest { + } + + @Test +- public void testExemplarsClassicHistogram() throws Exception { ++ void exemplarsClassicHistogram() throws Exception { + SpanContext spanContext = + new SpanContext() { + int callCount = 0; +@@ -1095,7 +1085,7 @@ class HistogramTest { + } + + @Test +- public void testCustomExemplarsClassicHistogram() ++ void customExemplarsClassicHistogram() + throws InterruptedException, NoSuchFieldException, IllegalAccessException { + + // TODO: This was copied from the old simpleclient, can probably be refactored. +@@ -1150,11 +1140,11 @@ class HistogramTest { + } + Exemplar exemplar = data.getExemplars().get(lowerBound, upperBound); + assertThat(exemplar) +- .as("No exemplar found in bucket [" + lowerBound + ", " + upperBound + "]") ++ .as("No exemplar found in bucket [%s, %s]", lowerBound, upperBound) + .isNotNull(); + assertThat(exemplar.getValue()).isEqualTo(value); + assertThat(exemplar.getLabels().size()) +- .as("" + exemplar.getLabels()) ++ .as("%s", exemplar.getLabels()) + .isEqualTo(labels.length / 2); + for (int i = 0; i < labels.length; i += 2) { + assertThat(exemplar.getLabels().getName(i / 2)).isEqualTo(labels[i]); +@@ -1163,7 +1153,7 @@ class HistogramTest { + } + + @Test +- public void testExemplarsNativeHistogram() throws NoSuchFieldException, IllegalAccessException { ++ void exemplarsNativeHistogram() throws NoSuchFieldException, IllegalAccessException { + + SpanContext spanContext = + new SpanContext() { +@@ -1206,17 +1196,17 @@ class HistogramTest { + + histogram.labelValues("/hello").observe(3.11); + histogram.labelValues("/world").observe(3.12); +- assertThat(getData(histogram, "path", "/hello").getExemplars().size()).isOne(); ++ assertThat(getData(histogram, "path", "/hello").getExemplars().size()).isEqualTo(1); + assertExemplarEquals( + ex1, getData(histogram, "path", "/hello").getExemplars().iterator().next()); +- assertThat(getData(histogram, "path", "/world").getExemplars().size()).isOne(); ++ assertThat(getData(histogram, "path", "/world").getExemplars().size()).isEqualTo(1); + assertExemplarEquals( + ex2, getData(histogram, "path", "/world").getExemplars().iterator().next()); + + histogram + .labelValues("/world") + .observeWithExemplar(3.13, Labels.of("key1", "value1", "key2", "value2")); +- assertThat(getData(histogram, "path", "/hello").getExemplars().size()).isOne(); ++ assertThat(getData(histogram, "path", "/hello").getExemplars().size()).isEqualTo(1); + assertExemplarEquals( + ex1, getData(histogram, "path", "/hello").getExemplars().iterator().next()); + assertThat(getData(histogram, "path", "/world").getExemplars().size()).isEqualTo(2); +@@ -1225,86 +1215,85 @@ class HistogramTest { + for (Exemplar exemplar : exemplars) { + exemplarList.add(exemplar); + } +- exemplarList.sort(Comparator.comparingDouble(Exemplar::getValue)); ++ exemplarList.sort(comparingDouble(Exemplar::getValue)); + assertThat(exemplars.size()).isEqualTo(2); + assertExemplarEquals(ex2, exemplarList.get(0)); + assertExemplarEquals(ex3, exemplarList.get(1)); + } + + @Test +- public void testIllegalLabelName() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Histogram.builder().name("test").labelNames("label", "le")); ++ void illegalLabelName() { ++ assertThatThrownBy(() -> Histogram.builder().name("test").labelNames("label", "le")) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testIllegalLabelNameConstLabels() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( ++ void illegalLabelNameConstLabels() { ++ assertThatThrownBy( + () -> + Histogram.builder() + .name("test") +- .constLabels(Labels.of("label1", "value1", "le", "0.3"))); ++ .constLabels(Labels.of("label1", "value1", "le", "0.3"))) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testIllegalLabelNamePrefix() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Histogram.builder().name("test").labelNames("__hello")); ++ void illegalLabelNamePrefix() { ++ assertThatThrownBy(() -> Histogram.builder().name("test").labelNames("__hello")) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testIllegalName() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Histogram.builder().name("my_namespace/server.durations")); ++ void illegalName() { ++ assertThatThrownBy(() -> Histogram.builder().name("my_namespace/server.durations")) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testNoName() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Histogram.builder().build()); ++ void noName() { ++ assertThatThrownBy(() -> Histogram.builder().build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testNullName() { +- assertThatExceptionOfType(NullPointerException.class) +- .isThrownBy(() -> Histogram.builder().name(null)); ++ void nullName() { ++ assertThatThrownBy(() -> Histogram.builder().name(null)) ++ .isInstanceOf(NullPointerException.class); + } + + @Test +- public void testDuplicateClassicBuckets() { ++ void duplicateClassicBuckets() { + Histogram histogram = + Histogram.builder().name("test").classicUpperBounds(0, 3, 17, 3, 21).build(); + List upperBounds = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getUpperBound) +- .collect(Collectors.toList()); +- assertThat(upperBounds) +- .isEqualTo(Arrays.asList(0.0, 3.0, 17.0, 21.0, Double.POSITIVE_INFINITY)); ++ .collect(toImmutableList()); ++ assertThat(upperBounds).containsExactly(0.0, 3.0, 17.0, 21.0, Double.POSITIVE_INFINITY); + } + + @Test +- public void testUnsortedBuckets() { ++ void unsortedBuckets() { + Histogram histogram = Histogram.builder().name("test").classicUpperBounds(0.2, 0.1).build(); + List upperBounds = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getUpperBound) +- .collect(Collectors.toList()); +- assertThat(upperBounds).isEqualTo(Arrays.asList(0.1, 0.2, Double.POSITIVE_INFINITY)); ++ .collect(toImmutableList()); ++ assertThat(upperBounds).containsExactly(0.1, 0.2, Double.POSITIVE_INFINITY); + } + + @Test +- public void testEmptyBuckets() { ++ void emptyBuckets() { + Histogram histogram = Histogram.builder().name("test").classicUpperBounds().build(); + List upperBounds = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getUpperBound) +- .collect(Collectors.toList()); +- assertThat(upperBounds).isEqualTo(Collections.singletonList(Double.POSITIVE_INFINITY)); ++ .collect(toImmutableList()); ++ assertThat(upperBounds).containsExactly(Double.POSITIVE_INFINITY); + } + + @Test +- public void testBucketsIncludePositiveInfinity() { ++ void bucketsIncludePositiveInfinity() { + Histogram histogram = + Histogram.builder() + .name("test") +@@ -1313,47 +1302,46 @@ class HistogramTest { + List upperBounds = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getUpperBound) +- .collect(Collectors.toList()); +- assertThat(upperBounds).isEqualTo(Arrays.asList(0.01, 0.1, 1.0, Double.POSITIVE_INFINITY)); ++ .collect(toImmutableList()); ++ assertThat(upperBounds).containsExactly(0.01, 0.1, 1.0, Double.POSITIVE_INFINITY); + } + + @Test +- public void testLinearBuckets() { ++ void linearBuckets() { + Histogram histogram = + Histogram.builder().name("test").classicLinearUpperBounds(0.1, 0.1, 10).build(); + List upperBounds = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getUpperBound) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + assertThat(upperBounds) +- .isEqualTo( +- Arrays.asList( +- 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, Double.POSITIVE_INFINITY)); ++ .containsExactly( ++ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, Double.POSITIVE_INFINITY); + } + + @Test +- public void testExponentialBuckets() { ++ void exponentialBuckets() { + Histogram histogram = + Histogram.builder().classicExponentialUpperBounds(2, 2.5, 3).name("test").build(); + List upperBounds = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getUpperBound) +- .collect(Collectors.toList()); +- assertThat(upperBounds).isEqualTo(Arrays.asList(2.0, 5.0, 12.5, Double.POSITIVE_INFINITY)); ++ .collect(toImmutableList()); ++ assertThat(upperBounds).containsExactly(2.0, 5.0, 12.5, Double.POSITIVE_INFINITY); + } + + @Test +- public void testBucketsIncludeNaN() { +- assertThatExceptionOfType(RuntimeException.class) +- .isThrownBy( +- () -> Histogram.builder().name("test").classicUpperBounds(0.01, 0.1, 1.0, Double.NaN)); ++ void bucketsIncludeNaN() { ++ assertThatThrownBy( ++ () -> Histogram.builder().name("test").classicUpperBounds(0.01, 0.1, 1.0, Double.NaN)) ++ .isInstanceOf(RuntimeException.class); + } + + @Test +- public void testNoLabelsDefaultZeroValue() { ++ void noLabelsDefaultZeroValue() { + Histogram noLabels = Histogram.builder().name("test").build(); +- assertThat(getBucket(noLabels, 0.005).getCount()).isZero(); +- assertThat(getData(noLabels).getCount()).isZero(); ++ assertThat(getBucket(noLabels, 0.005).getCount()).isEqualTo(0); ++ assertThat(getData(noLabels).getCount()).isEqualTo(0); + assertThat(getData(noLabels).getSum()).isEqualTo(0.0); + } + +@@ -1365,26 +1353,26 @@ class HistogramTest { + } + + @Test +- public void testObserve() { ++ void observe() { + Histogram noLabels = Histogram.builder().name("test").build(); + noLabels.observe(2); +- assertThat(getData(noLabels).getCount()).isOne(); +- assertThat(getData(noLabels).getSum()).isCloseTo(2.0, offset(.0)); +- assertThat(getBucket(noLabels, 1).getCount()).isZero(); +- assertThat(getBucket(noLabels, 2.5).getCount()).isOne(); ++ assertThat(getData(noLabels).getCount()).isEqualTo(1); ++ assertThat(getData(noLabels).getSum()).isEqualTo(2.0); ++ assertThat(getBucket(noLabels, 1).getCount()).isEqualTo(0); ++ assertThat(getBucket(noLabels, 2.5).getCount()).isEqualTo(1); + noLabels.observe(4); + assertThat(getData(noLabels).getCount()).isEqualTo(2); +- assertThat(getData(noLabels).getSum()).isCloseTo(6.0, offset(.0)); +- assertThat(getBucket(noLabels, 1).getCount()).isZero(); +- assertThat(getBucket(noLabels, 2.5).getCount()).isOne(); +- assertThat(getBucket(noLabels, 5).getCount()).isOne(); +- assertThat(getBucket(noLabels, 10).getCount()).isZero(); +- assertThat(getBucket(noLabels, Double.POSITIVE_INFINITY).getCount()).isZero(); ++ assertThat(getData(noLabels).getSum()).isEqualTo(6.0); ++ assertThat(getBucket(noLabels, 1).getCount()).isEqualTo(0); ++ assertThat(getBucket(noLabels, 2.5).getCount()).isEqualTo(1); ++ assertThat(getBucket(noLabels, 5).getCount()).isEqualTo(1); ++ assertThat(getBucket(noLabels, 10).getCount()).isEqualTo(0); ++ assertThat(getBucket(noLabels, Double.POSITIVE_INFINITY).getCount()).isEqualTo(0); + } + + @Test + // See https://github.com/prometheus/client_java/issues/646 +- public void testNegativeAmount() { ++ void negativeAmount() { + Histogram histogram = + Histogram.builder() + .name("histogram") +@@ -1405,27 +1393,27 @@ class HistogramTest { + List actualBucketCounts = + getData(histogram).getClassicBuckets().stream() + .map(ClassicHistogramBucket::getCount) +- .collect(Collectors.toList()); +- assertThat(actualBucketCounts).isEqualTo(expectedBucketCounts); ++ .collect(toImmutableList()); ++ assertThat(actualBucketCounts).containsExactlyElementsOf(expectedBucketCounts); + } + + @Test +- public void testBoundaryConditions() { ++ void boundaryConditions() { + Histogram histogram = Histogram.builder().name("test").build(); + histogram.observe(2.5); +- assertThat(getBucket(histogram, 1).getCount()).isZero(); +- assertThat(getBucket(histogram, 2.5).getCount()).isOne(); ++ assertThat(getBucket(histogram, 1).getCount()).isEqualTo(0); ++ assertThat(getBucket(histogram, 2.5).getCount()).isEqualTo(1); + + histogram.observe(Double.POSITIVE_INFINITY); +- assertThat(getBucket(histogram, 1).getCount()).isZero(); +- assertThat(getBucket(histogram, 2.5).getCount()).isOne(); +- assertThat(getBucket(histogram, 5).getCount()).isZero(); +- assertThat(getBucket(histogram, 10).getCount()).isZero(); +- assertThat(getBucket(histogram, Double.POSITIVE_INFINITY).getCount()).isOne(); ++ assertThat(getBucket(histogram, 1).getCount()).isEqualTo(0); ++ assertThat(getBucket(histogram, 2.5).getCount()).isEqualTo(1); ++ assertThat(getBucket(histogram, 5).getCount()).isEqualTo(0); ++ assertThat(getBucket(histogram, 10).getCount()).isEqualTo(0); ++ assertThat(getBucket(histogram, Double.POSITIVE_INFINITY).getCount()).isEqualTo(1); + } + + @Test +- public void testObserveWithLabels() { ++ void observeWithLabels() { + Histogram histogram = + Histogram.builder() + .name("test") +@@ -1441,20 +1429,19 @@ class HistogramTest { + getData(histogram, "env", "prod", "path", "/hello", "status", "500"); + assertThat(data200.getCount()).isEqualTo(2); + assertThat(data200.getSum()).isCloseTo(0.31, offset(0.0000001)); +- assertThat(data500.getCount()).isOne(); ++ assertThat(data500.getCount()).isEqualTo(1); + assertThat(data500.getSum()).isCloseTo(0.19, offset(0.0000001)); + histogram.labelValues("/hello", "200").observe(0.13); + data200 = getData(histogram, "env", "prod", "path", "/hello", "status", "200"); + data500 = getData(histogram, "env", "prod", "path", "/hello", "status", "500"); + assertThat(data200.getCount()).isEqualTo(3); + assertThat(data200.getSum()).isCloseTo(0.44, offset(0.0000001)); +- assertThat(data500.getCount()).isOne(); ++ assertThat(data500.getCount()).isEqualTo(1); + assertThat(data500.getSum()).isCloseTo(0.19, offset(0.0000001)); + } + + @Test +- public void testObserveMultithreaded() +- throws InterruptedException, ExecutionException, TimeoutException { ++ void observeMultithreaded() throws InterruptedException, ExecutionException, TimeoutException { + // Hard to test concurrency, but let's run a couple of observations in parallel and assert none + // gets lost. + Histogram histogram = Histogram.builder().name("test").labelNames("status").build(); +@@ -1485,7 +1472,7 @@ class HistogramTest { + List snapshots = future.get(5, TimeUnit.SECONDS); + long count = 0; + for (HistogramSnapshot snapshot : snapshots) { +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + HistogramSnapshot.HistogramDataPointSnapshot data = + snapshot.getDataPoints().stream().findFirst().orElseThrow(RuntimeException::new); + assertThat(data.getCount()) +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java +@@ -1,7 +1,7 @@ + package io.prometheus.metrics.core.metrics; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter; + import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_29_1.Metrics; +@@ -15,10 +15,10 @@ import java.io.IOException; + import java.nio.charset.StandardCharsets; + import org.junit.jupiter.api.Test; + +-class InfoTest { ++final class InfoTest { + + @Test +- public void testInfoStrippedFromName() { ++ void infoStrippedFromName() { + for (String name : + new String[] { + "jvm.runtime", "jvm_runtime", +@@ -37,7 +37,7 @@ class InfoTest { + } + + @Test +- public void testAddAndRemove() { ++ void addAndRemove() { + Info info = Info.builder().name("test_info").labelNames("a", "b").build(); + assertThat(info.collect().getDataPoints()).isEmpty(); + info.addLabelValues("val1", "val2"); +@@ -53,14 +53,14 @@ class InfoTest { + info.remove("val2", "val2"); + assertThat(info.collect().getDataPoints()).isEmpty(); + +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> info.addLabelValues("val1", "val2", "extra")) +- .withMessage( ++ assertThatThrownBy(() -> info.addLabelValues("val1", "val2", "extra")) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "Info test was created with 2 label names, but you called addLabelValues() with 3 label values."); + } + + @Test +- public void testSet() throws IOException { ++ void set() throws IOException { + Info info = + Info.builder() + .name("target_info") +@@ -75,19 +75,19 @@ class InfoTest { + "target_info{service_instance_id=\"123\",service_name=\"test\",service_version=\"2.0.0\"} 1\n", + info); + +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> info.setLabelValues("2.0.0", "extra")) +- .withMessage( ++ assertThatThrownBy(() -> info.setLabelValues("2.0.0", "extra")) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "Info target was created with 1 label names, but you called setLabelValues() with 2 label values."); + +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> info.remove("2.0.0", "extra")) +- .withMessage( ++ assertThatThrownBy(() -> info.remove("2.0.0", "extra")) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "Info target was created with 1 label names, but you called remove() with 2 label values."); + } + + @Test +- public void testConstLabelsOnly() throws IOException { ++ void constLabelsOnly() throws IOException { + Info info = + Info.builder() + .name("target_info") +@@ -99,23 +99,23 @@ class InfoTest { + + @Test + void unit() { +- assertThatExceptionOfType(UnsupportedOperationException.class) +- .isThrownBy(() -> Info.builder().unit(Unit.BYTES).build()) +- .withMessage("Info metrics cannot have a unit."); ++ assertThatThrownBy(() -> Info.builder().unit(Unit.BYTES).build()) ++ .isInstanceOf(UnsupportedOperationException.class) ++ .hasMessage("Info metrics cannot have a unit."); + } + + @Test +- public void testConstLabelsDuplicate1() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( +- () -> Info.builder().constLabels(Labels.of("a_1", "val1")).labelNames("a.1").build()); ++ void constLabelsDuplicate1() { ++ assertThatThrownBy( ++ () -> Info.builder().constLabels(Labels.of("a_1", "val1")).labelNames("a.1").build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testConstLabelsDuplicate2() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( +- () -> Info.builder().labelNames("a_1").constLabels(Labels.of("a.1", "val1")).build()); ++ void constLabelsDuplicate2() { ++ assertThatThrownBy( ++ () -> Info.builder().labelNames("a_1").constLabels(Labels.of("a.1", "val1")).build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + private void assertTextFormat(String expected, Info info) throws IOException { +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/SlidingWindowTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/SlidingWindowTest.java +@@ -8,7 +8,7 @@ import java.util.concurrent.atomic.AtomicLong; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class SlidingWindowTest { ++final class SlidingWindowTest { + + class Observer { + +@@ -25,12 +25,8 @@ class SlidingWindowTest { + } + assertThat(values) + .as( +- "Start time: " +- + startTime +- + ", current time: " +- + currentTimeMillis.get() +- + ", elapsed time: " +- + (currentTimeMillis.get() - startTime)) ++ "Start time: %s, current time: %s, elapsed time: %s", ++ startTime, currentTimeMillis.get(), currentTimeMillis.get() - startTime) + .isEqualTo(expectedList); + } + } +@@ -43,7 +39,7 @@ class SlidingWindowTest { + private final long timeBetweenRotateMillis = maxAgeSeconds * 1000 / ageBuckets + 2; + + @BeforeEach +- public void setUp() { ++ void setUp() { + startTime = System.currentTimeMillis(); + currentTimeMillis.set(startTime); + ringBuffer = +@@ -53,7 +49,7 @@ class SlidingWindowTest { + } + + @Test +- public void testRotate() { ++ void rotate() { + for (int i = 0; i < ageBuckets; i++) { + currentTimeMillis.addAndGet(timeBetweenRotateMillis); + ringBuffer.observe(1.0); +@@ -72,7 +68,7 @@ class SlidingWindowTest { + } + + @Test +- public void testMultiRotate() { ++ void multiRotate() { + ringBuffer.observe(1.0); + currentTimeMillis.addAndGet(2 * timeBetweenRotateMillis); // 2/5 of max aqe + ringBuffer.observe(2.0); +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/StateSetTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/StateSetTest.java +@@ -1,14 +1,14 @@ + package io.prometheus.metrics.core.metrics; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.StateSetSnapshot; + import java.util.Arrays; + import org.junit.jupiter.api.Test; + +-class StateSetTest { ++final class StateSetTest { + + enum MyFeatureFlag { + EXPERIMENTAL_FEATURE_1 { +@@ -27,7 +27,7 @@ class StateSetTest { + } + + @Test +- public void testEnumStateSet() { ++ void enumStateSet() { + StateSet stateSet = + StateSet.builder() + .name("feature_flags") +@@ -51,7 +51,7 @@ class StateSetTest { + } + + @Test +- public void testDefaultFalse() { ++ void defaultFalse() { + StateSet stateSet = + StateSet.builder().name("test").states("state1", "state2", "state3").build(); + assertThat(getData(stateSet).size()).isEqualTo(3); +@@ -65,9 +65,9 @@ class StateSetTest { + + @Test + void illegalName() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> StateSet.builder().name("state1").states("state1", "state2").build()) +- .withMessage( ++ assertThatThrownBy(() -> StateSet.builder().name("state1").states("state1", "state2").build()) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage( + "Label name state1 is illegal (can't use the metric name as label name in state set metrics)"); + } + +@@ -82,8 +82,8 @@ class StateSetTest { + } + + @Test +- public void testStatesCannotBeEmpty() { +- assertThatExceptionOfType(IllegalStateException.class) +- .isThrownBy(() -> StateSet.builder().name("invalid").build()); ++ void statesCannotBeEmpty() { ++ assertThatThrownBy(() -> StateSet.builder().name("invalid").build()) ++ .isInstanceOf(IllegalStateException.class); + } + } +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/StatefulMetricTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/StatefulMetricTest.java +@@ -6,10 +6,10 @@ import java.lang.reflect.Field; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class StatefulMetricTest { ++final class StatefulMetricTest { + + @Test +- public void testLabelRemoveWhileCollecting() throws Exception { ++ void labelRemoveWhileCollecting() throws Exception { + Counter counter = Counter.builder().name("test").labelNames("label1", "label2").build(); + Field data = counter.getClass().getSuperclass().getDeclaredField("data"); + data.setAccessible(true); +@@ -35,7 +35,7 @@ class StatefulMetricTest { + } + + @Test +- public void testClear() { ++ void clear() { + Counter counter = Counter.builder().name("test").labelNames("label1", "label2").build(); + counter.labelValues("a", "b").inc(3.0); + counter.labelValues("c", "d").inc(3.0); +@@ -50,7 +50,7 @@ class StatefulMetricTest { + } + + @Test +- public void testClearNoLabels() { ++ void clearNoLabels() { + Counter counter = Counter.builder().name("test").build(); + counter.inc(); + assertThat(counter.collect().getDataPoints()).hasSize(1); +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/SummaryTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/SummaryTest.java +@@ -1,7 +1,7 @@ + package io.prometheus.metrics.core.metrics; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.assertj.core.api.Assertions.fail; + import static org.assertj.core.data.Offset.offset; + +@@ -17,7 +17,7 @@ import java.util.List; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class SummaryTest { ++final class SummaryTest { + + private final Label label = new Label("name", "value"); + private final Labels labels = Labels.builder().label(label.getName(), label.getValue()).build(); +@@ -29,7 +29,7 @@ class SummaryTest { + private Summary noLabelsAndQuantiles; + + @BeforeEach +- public void setUp() { ++ void setUp() { + registry = new PrometheusRegistry(); + noLabels = + Summary.builder().name("nolabels").unit(Unit.SECONDS).help("help").register(registry); +@@ -62,16 +62,16 @@ class SummaryTest { + } + + @Test +- public void testObserve() { ++ void observe() { + noLabels.observe(2); +- assertThat(getCount(noLabels, Labels.EMPTY)).isOne(); ++ assertThat(getCount(noLabels, Labels.EMPTY)).isEqualTo(1); + assertThat(getSum(noLabels, Labels.EMPTY)).isCloseTo(2.0, offset(.001)); + noLabels.observe(3); + assertThat(getCount(noLabels, Labels.EMPTY)).isEqualTo(2); + assertThat(getSum(noLabels, Labels.EMPTY)).isCloseTo(5.0, offset(.001)); + + withLabels.labelValues(label.getValue()).observe(4); +- assertThat(getCount(withLabels, labels)).isOne(); ++ assertThat(getCount(withLabels, labels)).isEqualTo(1); + assertThat(getSum(withLabels, labels)).isCloseTo(4.0, offset(.001)); + + withLabels.labelValues(label.getValue()).observeWithExemplar(6, labels); +@@ -80,7 +80,7 @@ class SummaryTest { + } + + @Test +- public void testNegativeAmount() { ++ void negativeAmount() { + noLabels.observe(-1); + noLabels.observe(-3); + assertThat(getCount(noLabels, Labels.EMPTY)).isEqualTo(2); +@@ -88,7 +88,7 @@ class SummaryTest { + } + + @Test +- public void testQuantiles() { ++ void quantiles() { + int nSamples = 1000000; // simulate one million samples + + for (int i = 1; i <= nSamples; i++) { +@@ -113,7 +113,7 @@ class SummaryTest { + } + + @Test +- public void testMaxAge() throws InterruptedException { ++ void maxAge() throws InterruptedException { + Summary summary = + Summary.builder() + .quantile(0.99, 0.001) +@@ -132,10 +132,10 @@ class SummaryTest { + } + + @Test +- public void testTimer() { ++ void timer() { + int result = noLabels.time(() -> 123); + assertThat(result).isEqualTo(123); +- assertThat(getCount(noLabels, Labels.EMPTY)).isOne(); ++ assertThat(getCount(noLabels, Labels.EMPTY)).isEqualTo(1); + + try (Timer timer = noLabels.startTimer()) { + timer.observeDuration(); +@@ -144,33 +144,33 @@ class SummaryTest { + } + + @Test +- public void noLabelsDefaultZeroValue() { +- assertThat(getCount(noLabels, Labels.EMPTY)).isZero(); ++ void noLabelsDefaultZeroValue() { ++ assertThat(getCount(noLabels, Labels.EMPTY)).isEqualTo(0); + assertThat(getSum(noLabels, Labels.EMPTY)).isCloseTo(0.0, offset(.001)); + } + + @Test +- public void testBuilderInvalidNumberOfAgeBuckets() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Summary.builder().name("name").numberOfAgeBuckets(-1).build()); ++ void builderInvalidNumberOfAgeBuckets() { ++ assertThatThrownBy(() -> Summary.builder().name("name").numberOfAgeBuckets(-1).build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testBuilderInvalidMaxAge() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Summary.builder().name("name").maxAgeSeconds(-1).build()); ++ void builderInvalidMaxAge() { ++ assertThatThrownBy(() -> Summary.builder().name("name").maxAgeSeconds(-1).build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testBuilderInvalidQuantile() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Summary.builder().name("name").quantile(42).build()); ++ void builderInvalidQuantile() { ++ assertThatThrownBy(() -> Summary.builder().name("name").quantile(42).build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testBuilderInvalidQuantileError() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Summary.builder().name("name").quantile(0.5, 20).build()); ++ void builderInvalidQuantileError() { ++ assertThatThrownBy(() -> Summary.builder().name("name").quantile(0.5, 20).build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + + private double getQuantile(Summary summary, double quantile, Labels labels) { +@@ -188,7 +188,7 @@ class SummaryTest { + private SummarySnapshot.SummaryDataPointSnapshot getDatapoint(Summary summary, Labels labels) { + SummarySnapshot snapshot = summary.collect(); + List datapoints = snapshot.getDataPoints(); +- assertThat(datapoints.size()).isOne(); ++ assertThat(datapoints).hasSize(1); + SummarySnapshot.SummaryDataPointSnapshot datapoint = datapoints.get(0); + assertThat((Iterable) datapoint.getLabels()).isEqualTo(labels); + return datapoint; +--- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/SummaryWithCallbackTest.java ++++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/SummaryWithCallbackTest.java +@@ -1,7 +1,7 @@ + package io.prometheus.metrics.core.metrics; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.assertj.core.data.Offset.offset; + + import io.prometheus.metrics.model.snapshots.Quantile; +@@ -12,10 +12,10 @@ import java.util.List; + import java.util.concurrent.atomic.AtomicInteger; + import org.junit.jupiter.api.Test; + +-class SummaryWithCallbackTest { ++final class SummaryWithCallbackTest { + + @Test +- public void testGauge() { ++ void gauge() { + final AtomicInteger count = new AtomicInteger(1); + final AtomicInteger sum = new AtomicInteger(1); + final Quantiles quantiles = Quantiles.of(new Quantile(0.5, 10)); +@@ -32,7 +32,7 @@ class SummaryWithCallbackTest { + .build(); + SummarySnapshot snapshot = gauge.collect(); + +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + SummarySnapshot.SummaryDataPointSnapshot datapoint = snapshot.getDataPoints().get(0); + assertThat(datapoint.getCount()).isEqualTo(count.get()); + assertThat(datapoint.getSum()).isCloseTo(sum.doubleValue(), offset(0.1)); +@@ -42,16 +42,16 @@ class SummaryWithCallbackTest { + count.incrementAndGet(); + sum.incrementAndGet(); + snapshot = gauge.collect(); +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + datapoint = snapshot.getDataPoints().get(0); + assertThat(datapoint.getCount()).isEqualTo(count.get()); + assertThat(datapoint.getSum()).isCloseTo(sum.doubleValue(), offset(0.1)); + } + + @Test +- public void testSummaryNoCallback() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy( +- () -> SummaryWithCallback.builder().name("summary").labelNames("l1", "l2").build()); ++ void summaryNoCallback() { ++ assertThatThrownBy( ++ () -> SummaryWithCallback.builder().name("summary").labelNames("l1", "l2").build()) ++ .isInstanceOf(IllegalArgumentException.class); + } + } +--- a/prometheus-metrics-exporter-common/src/main/java/io/prometheus/metrics/exporter/common/PrometheusScrapeHandler.java ++++ b/prometheus-metrics-exporter-common/src/main/java/io/prometheus/metrics/exporter/common/PrometheusScrapeHandler.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.exporter.common; + ++import static java.nio.charset.StandardCharsets.UTF_8; ++ + import io.prometheus.metrics.config.ExporterFilterProperties; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.expositionformats.ExpositionFormatWriter; +@@ -10,7 +12,6 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import java.io.ByteArrayOutputStream; + import java.io.IOException; + import java.io.OutputStream; +-import java.nio.charset.StandardCharsets; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.Enumeration; +@@ -156,7 +157,7 @@ public class PrometheusScrapeHandler { + case "prometheus-protobuf": + String debugString = + expositionFormats.getPrometheusProtobufWriter().toDebugString(snapshots); +- body.write(debugString.getBytes(StandardCharsets.UTF_8)); ++ body.write(debugString.getBytes(UTF_8)); + break; + default: + body.write( +@@ -164,7 +165,7 @@ public class PrometheusScrapeHandler { + + debugParam + + ": Unsupported query parameter. Valid values are 'openmetrics', " + + "'text', and 'prometheus-protobuf'.") +- .getBytes(StandardCharsets.UTF_8)); ++ .getBytes(UTF_8)); + break; + } + return true; +--- a/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/DefaultHandler.java ++++ b/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/DefaultHandler.java +@@ -1,9 +1,10 @@ + package io.prometheus.metrics.exporter.httpserver; + ++import static java.nio.charset.StandardCharsets.UTF_8; ++ + import com.sun.net.httpserver.HttpExchange; + import com.sun.net.httpserver.HttpHandler; + import java.io.IOException; +-import java.nio.charset.StandardCharsets; + + /** Handler for the / endpoint */ + public class DefaultHandler implements HttpHandler { +@@ -66,7 +67,7 @@ public class DefaultHandler implements HttpHandler { + + "header for indicating which format it accepts.\n" + + "\n" + + "\n"; +- this.responseBytes = responseString.getBytes(StandardCharsets.UTF_8); ++ this.responseBytes = responseString.getBytes(UTF_8); + this.contentType = "text/html; charset=utf-8"; + } + +--- a/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HTTPServer.java ++++ b/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HTTPServer.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.exporter.httpserver; + ++import static com.google.common.base.Preconditions.checkArgument; ++import static com.google.common.base.Preconditions.checkState; ++ + import com.sun.net.httpserver.Authenticator; + import com.sun.net.httpserver.HttpContext; + import com.sun.net.httpserver.HttpExchange; +@@ -57,9 +60,7 @@ public class HTTPServer implements Closeable { + Authenticator authenticator, + String authenticatedSubjectAttributeName, + HttpHandler defaultHandler) { +- if (httpServer.getAddress() == null) { +- throw new IllegalArgumentException("HttpServer hasn't been bound to an address"); +- } ++ checkArgument(httpServer.getAddress() != null, "HttpServer hasn't been bound to an address"); + this.server = httpServer; + this.executorService = executorService; + registerHandler( +@@ -314,9 +315,7 @@ public class HTTPServer implements Closeable { + } + + private void assertNull(Object o, String msg) { +- if (o != null) { +- throw new IllegalStateException(msg); +- } ++ checkState(o == null, msg); + } + } + } +--- a/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HealthyHandler.java ++++ b/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HealthyHandler.java +@@ -1,9 +1,10 @@ + package io.prometheus.metrics.exporter.httpserver; + ++import static java.nio.charset.StandardCharsets.UTF_8; ++ + import com.sun.net.httpserver.HttpExchange; + import com.sun.net.httpserver.HttpHandler; + import java.io.IOException; +-import java.nio.charset.StandardCharsets; + + /** Handler for the /-/healthy endpoint */ + public class HealthyHandler implements HttpHandler { +@@ -13,7 +14,7 @@ public class HealthyHandler implements HttpHandler { + + public HealthyHandler() { + String responseString = "Exporter is healthy.\n"; +- this.responseBytes = responseString.getBytes(StandardCharsets.UTF_8); ++ this.responseBytes = responseString.getBytes(UTF_8); + this.contentType = "text/plain; charset=utf-8"; + } + +--- a/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HttpExchangeAdapter.java ++++ b/prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HttpExchangeAdapter.java +@@ -1,5 +1,9 @@ + package io.prometheus.metrics.exporter.httpserver; + ++import static java.nio.charset.StandardCharsets.UTF_8; ++import static java.util.Collections.emptyEnumeration; ++import static java.util.Collections.enumeration; ++ + import com.sun.net.httpserver.HttpExchange; + import io.prometheus.metrics.exporter.common.PrometheusHttpExchange; + import io.prometheus.metrics.exporter.common.PrometheusHttpRequest; +@@ -9,8 +13,6 @@ import java.io.OutputStream; + import java.io.PrintWriter; + import java.io.StringWriter; + import java.net.URI; +-import java.nio.charset.StandardCharsets; +-import java.util.Collections; + import java.util.Enumeration; + import java.util.List; + import java.util.logging.Level; +@@ -38,9 +40,9 @@ public class HttpExchangeAdapter implements PrometheusHttpExchange { + public Enumeration getHeaders(String name) { + List headers = httpExchange.getRequestHeaders().get(name); + if (headers == null) { +- return Collections.emptyEnumeration(); ++ return emptyEnumeration(); + } else { +- return Collections.enumeration(headers); ++ return enumeration(headers); + } + } + +@@ -108,7 +110,7 @@ public class HttpExchangeAdapter implements PrometheusHttpExchange { + PrintWriter printWriter = new PrintWriter(stringWriter); + printWriter.write("An Exception occurred while scraping metrics: "); + requestHandlerException.printStackTrace(new PrintWriter(printWriter)); +- byte[] stackTrace = stringWriter.toString().getBytes(StandardCharsets.UTF_8); ++ byte[] stackTrace = stringWriter.toString().getBytes(UTF_8); + httpExchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8"); + httpExchange.sendResponseHeaders(500, stackTrace.length); + httpExchange.getResponseBody().write(stackTrace); +--- a/prometheus-metrics-exporter-httpserver/src/test/java/io/prometheus/metrics/exporter/httpserver/HTTPServerTest.java ++++ b/prometheus-metrics-exporter-httpserver/src/test/java/io/prometheus/metrics/exporter/httpserver/HTTPServerTest.java +@@ -1,7 +1,8 @@ + package io.prometheus.metrics.exporter.httpserver; + ++import static java.nio.charset.StandardCharsets.UTF_8; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import com.sun.net.httpserver.Authenticator; + import com.sun.net.httpserver.HttpExchange; +@@ -15,7 +16,6 @@ import java.io.IOException; + import java.net.InetAddress; + import java.net.InetSocketAddress; + import java.net.Socket; +-import java.nio.charset.StandardCharsets; + import java.security.AccessController; + import java.security.NoSuchAlgorithmException; + import java.security.Principal; +@@ -24,11 +24,11 @@ import javax.net.ssl.SSLContext; + import javax.security.auth.Subject; + import org.junit.jupiter.api.Test; + +-public class HTTPServerTest { ++final class HTTPServerTest { + ++ @SuppressWarnings("removal") + @Test +- @SuppressWarnings({"removal"}) +- public void testSubjectDoAs() throws Exception { ++ void subjectDoAs() throws Exception { + + final String user = "joe"; + final Subject subject = new Subject(); +@@ -73,17 +73,15 @@ public class HTTPServerTest { + try (Socket socket = new Socket()) { + socket.connect(new InetSocketAddress("localhost", server.getPort())); + +- socket +- .getOutputStream() +- .write(("GET " + path + " HTTP/1.1 \r\n").getBytes(StandardCharsets.UTF_8)); +- socket.getOutputStream().write("HOST: localhost \r\n\r\n".getBytes(StandardCharsets.UTF_8)); ++ socket.getOutputStream().write(("GET " + path + " HTTP/1.1 \r\n").getBytes(UTF_8)); ++ socket.getOutputStream().write("HOST: localhost \r\n\r\n".getBytes(UTF_8)); + socket.getOutputStream().flush(); + + String actualResponse = ""; + byte[] resp = new byte[500]; + int read = socket.getInputStream().read(resp, 0, resp.length); + if (read > 0) { +- actualResponse = new String(resp, 0, read, StandardCharsets.UTF_8); ++ actualResponse = new String(resp, 0, read, UTF_8); + } + assertThat(actualResponse).contains(expected); + } +@@ -124,15 +122,15 @@ public class HTTPServerTest { + + @Test + void config() throws NoSuchAlgorithmException, IOException { +- assertThatExceptionOfType(IllegalStateException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + HTTPServer.builder() + .port(0) + .hostname("localhost") + .inetAddress(InetAddress.getByName("localhost")) + .buildAndStart()) +- .withMessage("cannot configure 'inetAddress' and 'hostname' at the same time"); ++ .isInstanceOf(IllegalStateException.class) ++ .hasMessage("cannot configure 'inetAddress' and 'hostname' at the same time"); + + // ssl doesn't work without in tests + run( +--- a/prometheus-metrics-exporter-httpserver/src/test/java/io/prometheus/metrics/exporter/httpserver/MetricsHandlerTest.java ++++ b/prometheus-metrics-exporter-httpserver/src/test/java/io/prometheus/metrics/exporter/httpserver/MetricsHandlerTest.java +@@ -9,7 +9,7 @@ import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.registry.PrometheusRegistry; + import org.junit.jupiter.api.Test; + +-class MetricsHandlerTest { ++final class MetricsHandlerTest { + + @Test + void ctor() { +@@ -24,7 +24,7 @@ class MetricsHandlerTest { + .extracting("registry") + .isEqualTo(registry); + +- PrometheusProperties properties = mock(PrometheusProperties.class, RETURNS_MOCKS); ++ PrometheusProperties properties = mock(RETURNS_MOCKS); + + assertThat(new MetricsHandler(properties)) + .extracting("prometheusScrapeHandler") +--- a/prometheus-metrics-exporter-opentelemetry-otel-agent-resources/src/main/java/io/prometheus/otelagent/ResourceAttributesFromOtelAgent.java ++++ b/prometheus-metrics-exporter-opentelemetry-otel-agent-resources/src/main/java/io/prometheus/otelagent/ResourceAttributesFromOtelAgent.java +@@ -1,7 +1,10 @@ + package io.prometheus.otelagent; + ++import static com.google.common.base.Preconditions.checkState; + import static java.nio.file.Files.createTempDirectory; ++import static java.util.Collections.unmodifiableMap; + ++import com.google.common.collect.ImmutableMap; + import java.io.File; + import java.io.InputStream; + import java.lang.reflect.Field; +@@ -11,7 +14,6 @@ import java.net.URLClassLoader; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.StandardCopyOption; +-import java.util.Collections; + import java.util.HashMap; + import java.util.Map; + +@@ -63,7 +65,7 @@ public class ResourceAttributesFromOtelAgent { + result.put(entry.getKey().toString(), entry.getValue().toString()); + } + } +- return Collections.unmodifiableMap(result); ++ return unmodifiableMap(result); + } + } + } finally { +@@ -72,7 +74,7 @@ public class ResourceAttributesFromOtelAgent { + } catch (Exception ignored) { + // ignore + } +- return Collections.emptyMap(); ++ return ImmutableMap.of(); + } + + private static Object getField(String name, Object obj) throws Exception { +@@ -93,14 +95,11 @@ public class ResourceAttributesFromOtelAgent { + for (int i = 0; i < OTEL_JARS.length; i++) { + InputStream inputStream = + Thread.currentThread().getContextClassLoader().getResourceAsStream("lib/" + OTEL_JARS[i]); +- if (inputStream == null) { +- throw new IllegalStateException( +- "Error initializing " +- + instrumentationScopeName +- + ": lib/" +- + OTEL_JARS[i] +- + " not found in classpath."); +- } ++ checkState( ++ inputStream != null, ++ "Error initializing %s: lib/%s not found in classpath.", ++ instrumentationScopeName, ++ OTEL_JARS[i]); + File outputFile = tmpDir.resolve(OTEL_JARS[i]).toFile(); + Files.copy(inputStream, outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + inputStream.close(); +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.exporter.opentelemetry; + ++import static com.google.common.base.Preconditions.checkArgument; ++import static com.google.common.base.Preconditions.checkState; ++ + import io.opentelemetry.sdk.metrics.export.MetricReader; + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.model.registry.PrometheusRegistry; +@@ -60,10 +63,10 @@ public class OpenTelemetryExporter implements AutoCloseable { + * href="https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_protocol">OTEL_EXPORTER_OTLP_PROTOCOL. + */ + public Builder protocol(String protocol) { +- if (!protocol.equals("grpc") && !protocol.equals("http/protobuf")) { +- throw new IllegalArgumentException( +- protocol + ": Unsupported protocol. Expecting grpc or http/protobuf"); +- } ++ checkArgument( ++ protocol.equals("grpc") || protocol.equals("http/protobuf"), ++ "%s: Unsupported protocol. Expecting grpc or http/protobuf", ++ protocol); + this.protocol = protocol; + return this; + } +@@ -109,9 +112,7 @@ public class OpenTelemetryExporter implements AutoCloseable { + * but in seconds rather than milliseconds. + */ + public Builder intervalSeconds(int intervalSeconds) { +- if (intervalSeconds <= 0) { +- throw new IllegalStateException(intervalSeconds + ": expecting a push interval > 0s"); +- } ++ checkState(intervalSeconds > 0, "%s: expecting a push interval > 0s", intervalSeconds); + this.interval = intervalSeconds + "s"; + return this; + } +@@ -124,9 +125,7 @@ public class OpenTelemetryExporter implements AutoCloseable { + * but in seconds rather than milliseconds. + */ + public Builder timeoutSeconds(int timeoutSeconds) { +- if (timeoutSeconds <= 0) { +- throw new IllegalStateException(timeoutSeconds + ": expecting a push interval > 0s"); +- } ++ checkState(timeoutSeconds > 0, "%s: expecting a push interval > 0s", timeoutSeconds); + this.timeout = timeoutSeconds + "s"; + return this; + } +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/PrometheusInstrumentationScope.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/PrometheusInstrumentationScope.java +@@ -1,20 +1,22 @@ + package io.prometheus.metrics.exporter.opentelemetry; + ++import static com.google.common.base.Preconditions.checkState; ++ + import io.opentelemetry.sdk.common.InstrumentationScopeInfo; + import java.util.Properties; + + class PrometheusInstrumentationScope { + +- private static final String instrumentationScopePropertiesFile = ++ private static final String INSTRUMENTATION_SCOPE_PROPERTIES_FILE = + "instrumentationScope.properties"; +- private static final String instrumentationScopeNameKey = "instrumentationScope.name"; +- private static final String instrumentationScopeVersionKey = "instrumentationScope.version"; ++ private static final String INSTRUMENTATION_SCOPE_NAME_KEY = "instrumentationScope.name"; ++ private static final String INSTRUMENTATION_SCOPE_VERSION_KEY = "instrumentationScope.version"; + + public static InstrumentationScopeInfo loadInstrumentationScopeInfo() { + return loadInstrumentationScopeInfo( +- instrumentationScopePropertiesFile, +- instrumentationScopeNameKey, +- instrumentationScopeVersionKey); ++ INSTRUMENTATION_SCOPE_PROPERTIES_FILE, ++ INSTRUMENTATION_SCOPE_NAME_KEY, ++ INSTRUMENTATION_SCOPE_VERSION_KEY); + } + + static InstrumentationScopeInfo loadInstrumentationScopeInfo( +@@ -24,23 +26,17 @@ class PrometheusInstrumentationScope { + properties.load( + PrometheusInstrumentationScope.class.getClassLoader().getResourceAsStream(path)); + String instrumentationScopeName = properties.getProperty(nameKey); +- if (instrumentationScopeName == null) { +- throw new IllegalStateException( +- "Prometheus metrics library initialization error: " +- + nameKey +- + " not found in " +- + path +- + " in classpath."); +- } ++ checkState( ++ instrumentationScopeName != null, ++ "Prometheus metrics library initialization error: %s not found in %s in classpath.", ++ nameKey, ++ path); + String instrumentationScopeVersion = properties.getProperty(versionKey); +- if (instrumentationScopeVersion == null) { +- throw new IllegalStateException( +- "Prometheus metrics library initialization error: " +- + versionKey +- + " not found in " +- + path +- + " in classpath."); +- } ++ checkState( ++ instrumentationScopeVersion != null, ++ "Prometheus metrics library initialization error: %s not found in %s in classpath.", ++ versionKey, ++ path); + return InstrumentationScopeInfo.builder(instrumentationScopeName) + .setVersion(instrumentationScopeVersion) + .build(); +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusClassicHistogram.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusClassicHistogram.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ + import io.opentelemetry.sdk.metrics.data.AggregationTemporality; + import io.opentelemetry.sdk.metrics.data.HistogramData; + import io.opentelemetry.sdk.metrics.data.HistogramPointData; +@@ -10,7 +12,6 @@ import java.util.ArrayList; + import java.util.Collection; + import java.util.List; + import java.util.Objects; +-import java.util.stream.Collectors; + + class PrometheusClassicHistogram extends PrometheusData + implements HistogramData { +@@ -23,7 +24,7 @@ class PrometheusClassicHistogram extends PrometheusData + snapshot.getDataPoints().stream() + .map(dataPoint -> toOtelDataPoint(dataPoint, currentTimeMillis)) + .filter(Objects::nonNull) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusCounter.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusCounter.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ + import io.opentelemetry.sdk.metrics.data.AggregationTemporality; + import io.opentelemetry.sdk.metrics.data.DoublePointData; + import io.opentelemetry.sdk.metrics.data.MetricDataType; +@@ -7,7 +9,6 @@ import io.opentelemetry.sdk.metrics.data.SumData; + import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import java.util.Collection; + import java.util.List; +-import java.util.stream.Collectors; + + class PrometheusCounter extends PrometheusData + implements SumData { +@@ -19,7 +20,7 @@ class PrometheusCounter extends PrometheusData + this.points = + snapshot.getDataPoints().stream() + .map(dataPoint -> toOtelDataPoint(dataPoint, currentTimeMillis)) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusData.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusData.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ ++import com.google.common.collect.ImmutableList; + import io.opentelemetry.api.common.Attributes; + import io.opentelemetry.api.common.AttributesBuilder; + import io.opentelemetry.api.trace.SpanContext; +@@ -15,10 +18,8 @@ import io.prometheus.metrics.model.snapshots.Exemplar; + import io.prometheus.metrics.model.snapshots.Exemplars; + import io.prometheus.metrics.model.snapshots.Label; + import io.prometheus.metrics.model.snapshots.Labels; +-import java.util.Collections; + import java.util.List; + import java.util.concurrent.TimeUnit; +-import java.util.stream.Collectors; + import java.util.stream.StreamSupport; + + abstract class PrometheusData implements Data { +@@ -47,7 +48,7 @@ abstract class PrometheusData implements Data { + + protected List convertExemplar(Exemplar exemplar) { + if (exemplar == null) { +- return Collections.emptyList(); ++ return ImmutableList.of(); + } + return convertExemplars(Exemplars.of(exemplar)); + } +@@ -55,7 +56,7 @@ abstract class PrometheusData implements Data { + protected List convertExemplars(Exemplars exemplars) { + return StreamSupport.stream(exemplars.spliterator(), false) + .map(this::toDoubleExemplarData) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + protected DoubleExemplarData toDoubleExemplarData(Exemplar exemplar) { +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusGauge.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusGauge.java +@@ -1,12 +1,13 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ + import io.opentelemetry.sdk.metrics.data.DoublePointData; + import io.opentelemetry.sdk.metrics.data.GaugeData; + import io.opentelemetry.sdk.metrics.data.MetricDataType; + import io.prometheus.metrics.model.snapshots.GaugeSnapshot; + import java.util.Collection; + import java.util.List; +-import java.util.stream.Collectors; + + class PrometheusGauge extends PrometheusData + implements GaugeData { +@@ -18,7 +19,7 @@ class PrometheusGauge extends PrometheusData + this.points = + snapshot.getDataPoints().stream() + .map(dataPoint -> toOtelDataPoint(dataPoint, currentTimeMillis)) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusInfo.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusInfo.java +@@ -1,14 +1,15 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ ++import com.google.common.collect.ImmutableList; + import io.opentelemetry.sdk.metrics.data.AggregationTemporality; + import io.opentelemetry.sdk.metrics.data.DoublePointData; + import io.opentelemetry.sdk.metrics.data.MetricDataType; + import io.opentelemetry.sdk.metrics.data.SumData; + import io.prometheus.metrics.model.snapshots.InfoSnapshot; + import java.util.Collection; +-import java.util.Collections; + import java.util.List; +-import java.util.stream.Collectors; + + @SuppressWarnings("this-escape") + public class PrometheusInfo extends PrometheusData +@@ -21,7 +22,7 @@ public class PrometheusInfo extends PrometheusData + this.points = + snapshot.getDataPoints().stream() + .map(dataPoint -> toOtelDataPoint(dataPoint, currentTimeMillis)) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +@@ -46,6 +47,6 @@ public class PrometheusInfo extends PrometheusData + getStartEpochNanos(dataPoint), + getEpochNanos(dataPoint, currentTimeMillis), + labelsToAttributes(dataPoint.getLabels()), +- Collections.emptyList()); ++ ImmutableList.of()); + } + } +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusNativeHistogram.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusNativeHistogram.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ + import io.opentelemetry.sdk.metrics.data.AggregationTemporality; + import io.opentelemetry.sdk.metrics.data.ExponentialHistogramBuckets; + import io.opentelemetry.sdk.metrics.data.ExponentialHistogramData; +@@ -10,7 +12,6 @@ import io.prometheus.metrics.model.snapshots.NativeHistogramBuckets; + import java.util.Collection; + import java.util.List; + import java.util.Objects; +-import java.util.stream.Collectors; + + class PrometheusNativeHistogram extends PrometheusData + implements ExponentialHistogramData { +@@ -23,7 +24,7 @@ class PrometheusNativeHistogram extends PrometheusData toOtelDataPoint(dataPoint, currentTimeMillis)) + .filter(Objects::nonNull) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusStateSet.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusStateSet.java +@@ -1,5 +1,6 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import com.google.common.collect.ImmutableList; + import io.opentelemetry.sdk.metrics.data.AggregationTemporality; + import io.opentelemetry.sdk.metrics.data.DoublePointData; + import io.opentelemetry.sdk.metrics.data.MetricDataType; +@@ -8,7 +9,6 @@ import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.StateSetSnapshot; + import java.util.ArrayList; + import java.util.Collection; +-import java.util.Collections; + import java.util.List; + + public class PrometheusStateSet extends PrometheusData +@@ -55,6 +55,6 @@ public class PrometheusStateSet extends PrometheusData + dataPoint + .getLabels() + .merge(Labels.of(snapshot.getMetadata().getName(), dataPoint.getName(i)))), +- Collections.emptyList()); ++ ImmutableList.of()); + } + } +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusSummary.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusSummary.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ + import io.opentelemetry.sdk.metrics.data.MetricDataType; + import io.opentelemetry.sdk.metrics.data.SummaryData; + import io.opentelemetry.sdk.metrics.data.SummaryPointData; +@@ -7,7 +9,6 @@ import io.prometheus.metrics.model.snapshots.Quantile; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; + import java.util.Collection; + import java.util.List; +-import java.util.stream.Collectors; + + class PrometheusSummary extends PrometheusData implements SummaryData { + +@@ -18,7 +19,7 @@ class PrometheusSummary extends PrometheusData implements Summ + this.points = + snapshot.getDataPoints().stream() + .map(dataPoint -> toOtelDataPoint(dataPoint, currentTimeMillis)) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +--- a/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusUnknown.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/main/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusUnknown.java +@@ -1,12 +1,13 @@ + package io.prometheus.metrics.exporter.opentelemetry.otelmodel; + ++import static com.google.common.collect.ImmutableList.toImmutableList; ++ + import io.opentelemetry.sdk.metrics.data.DoublePointData; + import io.opentelemetry.sdk.metrics.data.GaugeData; + import io.opentelemetry.sdk.metrics.data.MetricDataType; + import io.prometheus.metrics.model.snapshots.UnknownSnapshot; + import java.util.Collection; + import java.util.List; +-import java.util.stream.Collectors; + + class PrometheusUnknown extends PrometheusData + implements GaugeData { +@@ -18,7 +19,7 @@ class PrometheusUnknown extends PrometheusData + this.points = + snapshot.getDataPoints().stream() + .map(dataPoint -> toOtelDataPoint(dataPoint, currentTimeMillis)) +- .collect(Collectors.toList()); ++ .collect(toImmutableList()); + } + + @Override +--- a/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/ExemplarTest.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/ExemplarTest.java +@@ -9,7 +9,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; + import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; + import static com.github.tomakehurst.wiremock.client.WireMock.verify; + import static java.util.concurrent.TimeUnit.SECONDS; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.awaitility.Awaitility.await; + + import com.github.tomakehurst.wiremock.http.Request; +@@ -35,7 +35,7 @@ import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + + @WireMockTest(httpPort = 4317) +-class ExemplarTest { ++final class ExemplarTest { + private static final String ENDPOINT_PATH = "/v1/metrics"; + private static final int TIMEOUT = 3; + private static final String INSTRUMENTATION_SCOPE_NAME = "testInstrumentationScope"; +@@ -45,7 +45,7 @@ class ExemplarTest { + private OpenTelemetryExporter openTelemetryExporter; + + @BeforeEach +- public void setUp() { ++ void setUp() { + openTelemetryExporter = + OpenTelemetryExporter.builder() + .endpoint("http://localhost:4317") +@@ -64,14 +64,14 @@ class ExemplarTest { + } + + @AfterEach +- public void tearDown() { ++ void tearDown() { + PrometheusRegistry.defaultRegistry.unregister(testCounter); + openTelemetryExporter.close(); + } + +- @Test + @SuppressWarnings("try") +- public void sampledExemplarIsForwarded() { ++ @Test ++ void sampledExemplarIsForwarded() { + try (SdkTracerProvider sdkTracerProvider = + SdkTracerProvider.builder().setSampler(Sampler.alwaysOn()).build()) { + +@@ -95,9 +95,9 @@ class ExemplarTest { + }); + } + +- @Test + @SuppressWarnings("try") +- public void notSampledExemplarIsNotForwarded() { ++ @Test ++ void notSampledExemplarIsNotForwarded() { + try (SdkTracerProvider sdkTracerProvider = + SdkTracerProvider.builder().setSampler(Sampler.alwaysOff()).build()) { + +@@ -108,8 +108,7 @@ class ExemplarTest { + } + } + +- assertThatExceptionOfType(ConditionTimeoutException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + await() + .atMost(TIMEOUT, SECONDS) +@@ -122,7 +121,8 @@ class ExemplarTest { + .withHeader("Content-Type", equalTo("application/x-protobuf")) + .andMatching(getExemplarCountMatcher(1))); + return true; +- })); ++ })) ++ .isInstanceOf(ConditionTimeoutException.class); + } + + private static ValueMatcher getExemplarCountMatcher(int expectedCount) { +--- a/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/ExportTest.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/ExportTest.java +@@ -2,6 +2,7 @@ package io.prometheus.metrics.exporter.opentelemetry; + + import static org.assertj.core.api.Assertions.assertThat; + ++import com.google.common.collect.ImmutableList; + import io.opentelemetry.api.common.AttributeKey; + import io.opentelemetry.api.common.Attributes; + import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +@@ -23,13 +24,12 @@ import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.Unit; + import io.prometheus.metrics.model.snapshots.UnknownSnapshot; + import java.lang.reflect.Field; +-import java.util.Collections; + import java.util.List; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.extension.RegisterExtension; + +-public class ExportTest { ++final class ExportTest { + + private static final Attributes ATTRIBUTES = + Attributes.of(AttributeKey.stringKey("label"), "val", AttributeKey.stringKey("key"), "value"); +@@ -173,7 +173,7 @@ public class ExportTest { + buckets + .hasOffset(-1) + .hasTotalCount(1) +- .hasCounts(Collections.singletonList(1L))))); ++ .hasCounts(ImmutableList.of(1L))))); + } + + @Test +--- a/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/OtelAutoConfigTest.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/OtelAutoConfigTest.java +@@ -1,6 +1,7 @@ + package io.prometheus.metrics.exporter.opentelemetry; + + import static org.assertj.core.api.Assertions.assertThat; ++import static org.junit.jupiter.params.provider.Arguments.arguments; + + import com.google.common.collect.ImmutableMap; + import io.opentelemetry.api.common.AttributeKey; +@@ -9,7 +10,6 @@ import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; + import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; + import io.prometheus.metrics.config.ExporterOpenTelemetryProperties; + import io.prometheus.metrics.config.PrometheusPropertiesLoader; +-import java.util.Collections; + import java.util.HashMap; + import java.util.Map; + import java.util.Optional; +@@ -21,12 +21,12 @@ import org.junit.jupiter.params.ParameterizedTest; + import org.junit.jupiter.params.provider.Arguments; + import org.junit.jupiter.params.provider.MethodSource; + +-class OtelAutoConfigTest { ++final class OtelAutoConfigTest { + + static class TestCase { + Map systemProperties = new HashMap<>(); +- Map> expectedProperties = Collections.emptyMap(); +- Map expectedResourceAttributes = Collections.emptyMap(); ++ Map> expectedProperties = ImmutableMap.of(); ++ Map expectedResourceAttributes = ImmutableMap.of(); + Consumer exporterBuilder; + Consumer propertiesBuilder; + +@@ -61,7 +61,7 @@ class OtelAutoConfigTest { + + public static Stream testCases() { + return Stream.of( +- Arguments.of( ++ arguments( + "values from builder", + new TestCase() + .expectedProperties( +@@ -79,7 +79,7 @@ class OtelAutoConfigTest { + "otel.service.name", + Optional.of("builder-service"))) + .expectedResourceAttributes( +- Map.of( ++ ImmutableMap.of( + "key", + "builder-value", + "service.name", +@@ -91,14 +91,14 @@ class OtelAutoConfigTest { + "service.version", + "builder-version")) + .exporterBuilder(OtelAutoConfigTest::setBuilderValues)), +- Arguments.of( ++ arguments( + "builder endpoint with path", + new TestCase() + .expectedProperties( + ImmutableMap.of( + "otel.exporter.otlp.endpoint", Optional.of("http://builder:4318/"))) + .exporterBuilder(builder -> builder.endpoint("http://builder:4318/v1/metrics"))), +- Arguments.of( ++ arguments( + "values from otel have precedence over builder", + new TestCase() + .expectedProperties( +@@ -128,7 +128,7 @@ class OtelAutoConfigTest { + "otel-version")) + .exporterBuilder(OtelAutoConfigTest::setBuilderValues) + .systemProperties(otelOverrides())), +- Arguments.of( ++ arguments( + "values from prom properties have precedence over builder and otel", + new TestCase() + .expectedProperties( +@@ -177,7 +177,7 @@ class OtelAutoConfigTest { + "io.prometheus.exporter.opentelemetry.resourceAttributes", + "key=prom-value") + .build())), +- Arguments.of( ++ arguments( + "values from prom properties builder have precedence over builder and otel", + new TestCase() + .expectedProperties( +@@ -250,8 +250,8 @@ class OtelAutoConfigTest { + .resourceAttribute("key", "builder-value"); + } + +- @ParameterizedTest(name = "{0}") + @MethodSource("testCases") ++ @ParameterizedTest(name = "{0}") + void properties(String name, TestCase testCase) { + testCase.systemProperties.forEach(System::setProperty); + +@@ -272,9 +272,10 @@ class OtelAutoConfigTest { + OtelAutoConfig.getResourceField(sdk).getAttributes().asMap(); + testCase.expectedProperties.forEach( + (key, value) -> { +- AbstractStringAssert o = assertThat(config.getString(key)).describedAs("key=" + key); ++ AbstractStringAssert o = ++ assertThat(config.getString(key)).describedAs("key=%s", key); + if (value.isPresent()) { +- o.isEqualTo(value.get()); ++ o.isEqualTo(value.orElseThrow()); + } else { + o.isNull(); + } +@@ -282,7 +283,7 @@ class OtelAutoConfigTest { + testCase.expectedResourceAttributes.forEach( + (key, value) -> + assertThat(map.get(AttributeKey.stringKey(key))) +- .describedAs("key=" + key) ++ .describedAs("key=%s", key) + .hasToString(value)); + } finally { + testCase.systemProperties.keySet().forEach(System::clearProperty); +--- a/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/PrometheusInstrumentationScopeTest.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/PrometheusInstrumentationScopeTest.java +@@ -1,38 +1,38 @@ + package io.prometheus.metrics.exporter.opentelemetry; + +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.junit.jupiter.api.Assertions.*; + + import org.junit.jupiter.api.Test; + +-class PrometheusInstrumentationScopeTest { ++final class PrometheusInstrumentationScopeTest { + + @Test + void loadInstrumentationScopeInfo() { +- assertThatExceptionOfType(IllegalStateException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + PrometheusInstrumentationScope.loadInstrumentationScopeInfo( + "path", "name", "version")) +- .withMessage( ++ .isInstanceOf(IllegalStateException.class) ++ .hasMessage( + "Prometheus metrics library initialization error: Failed to read path from classpath."); + +- assertThatExceptionOfType(IllegalStateException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + PrometheusInstrumentationScope.loadInstrumentationScopeInfo( + "instrumentationScope.properties", "name", "version")) +- .havingRootCause() +- .withMessage( ++ .isInstanceOf(IllegalStateException.class) ++ .rootCause() ++ .hasMessage( + "Prometheus metrics library initialization error: name not found in instrumentationScope.properties in classpath."); + +- assertThatExceptionOfType(IllegalStateException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> + PrometheusInstrumentationScope.loadInstrumentationScopeInfo( + "instrumentationScope.properties", "instrumentationScope.name", "version")) +- .havingRootCause() +- .withMessage( ++ .isInstanceOf(IllegalStateException.class) ++ .rootCause() ++ .hasMessage( + "Prometheus metrics library initialization error: version not found in instrumentationScope.properties in classpath."); + } + } +--- a/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusMetricDataTest.java ++++ b/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusMetricDataTest.java +@@ -7,7 +7,7 @@ import io.prometheus.metrics.model.snapshots.Unit; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class PrometheusMetricDataTest { ++final class PrometheusMetricDataTest { + + Map translations = + Map.ofEntries( +--- a/prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/DefaultJobLabelDetector.java ++++ b/prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/DefaultJobLabelDetector.java +@@ -3,7 +3,6 @@ package io.prometheus.metrics.exporter.pushgateway; + import java.nio.file.Files; + import java.nio.file.InvalidPathException; + import java.nio.file.Path; +-import java.nio.file.Paths; + + /** + * The default {@code job} label is the name of the JAR file being executed. +@@ -51,7 +50,7 @@ class DefaultJobLabelDetector { + private static Path pathIfExists(String programArguments) { + Path candidate; + try { +- candidate = Paths.get(programArguments); ++ candidate = Path.of(programArguments); + } catch (InvalidPathException e) { + return null; + } +--- a/prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/PushGateway.java ++++ b/prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/PushGateway.java +@@ -1,6 +1,9 @@ + package io.prometheus.metrics.exporter.pushgateway; + + import static io.prometheus.metrics.exporter.pushgateway.Scheme.HTTP; ++import static java.nio.charset.StandardCharsets.UTF_8; ++import static java.util.Collections.unmodifiableMap; ++import static java.util.Objects.requireNonNull; + + import io.prometheus.metrics.config.ExporterPushgatewayProperties; + import io.prometheus.metrics.config.PrometheusProperties; +@@ -23,9 +26,7 @@ import java.net.URI; + import java.net.URL; + import java.net.URLEncoder; + import java.net.UnknownHostException; +-import java.nio.charset.StandardCharsets; + import java.util.Base64; +-import java.util.Collections; + import java.util.HashMap; + import java.util.Map; + import java.util.TreeMap; +@@ -92,7 +93,7 @@ public class PushGateway { + Map requestHeaders) { + this.registry = registry; + this.url = url; +- this.requestHeaders = Collections.unmodifiableMap(new HashMap<>(requestHeaders)); ++ this.requestHeaders = unmodifiableMap(new HashMap<>(requestHeaders)); + this.connectionFactory = connectionFactory; + writer = getWriter(format); + if (!writer.isAvailable()) { +@@ -275,9 +276,7 @@ public class PushGateway { + + /** Default is {@link Format#PROMETHEUS_PROTOBUF}. */ + public Builder format(Format format) { +- if (format == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(format); + this.format = format; + return this; + } +@@ -288,9 +287,7 @@ public class PushGateway { + * property. + */ + public Builder address(String address) { +- if (address == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(address); + this.address = address; + return this; + } +@@ -300,7 +297,7 @@ public class PushGateway { + if (user == null || password == null) { + throw new NullPointerException(); + } +- byte[] credentialsBytes = (user + ":" + password).getBytes(StandardCharsets.UTF_8); ++ byte[] credentialsBytes = (user + ":" + password).getBytes(UTF_8); + String encoded = Base64.getEncoder().encodeToString(credentialsBytes); + requestHeaders.put("Authorization", String.format("Basic %s", encoded)); + return this; +@@ -308,9 +305,7 @@ public class PushGateway { + + /** Bearer token authorization when pushing to the Pushgateway. */ + public Builder bearerToken(String token) { +- if (token == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(token); + requestHeaders.put("Authorization", String.format("Bearer %s", token)); + return this; + } +@@ -320,9 +315,7 @@ public class PushGateway { + * at runtime with the {@code io.prometheus.exporter.pushgateway.scheme} property. + */ + public Builder scheme(Scheme scheme) { +- if (scheme == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(scheme); + this.scheme = scheme; + return this; + } +@@ -334,9 +327,7 @@ public class PushGateway { + * of a custom connection factory that skips SSL certificate validation for HTTPS connections. + */ + public Builder connectionFactory(HttpConnectionFactory connectionFactory) { +- if (connectionFactory == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(connectionFactory); + this.connectionFactory = connectionFactory; + return this; + } +@@ -347,9 +338,7 @@ public class PushGateway { + * io.prometheus.exporter.pushgateway.job} property. + */ + public Builder job(String job) { +- if (job == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(job); + this.job = job; + return this; + } +@@ -373,9 +362,7 @@ public class PushGateway { + + /** Push metrics from this registry instead of {@link PrometheusRegistry#defaultRegistry}. */ + public Builder registry(PrometheusRegistry registry) { +- if (registry == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(registry); + this.registry = registry; + return this; + } +@@ -443,7 +430,7 @@ public class PushGateway { + + private String base64url(String v) { + return Base64.getEncoder() +- .encodeToString(v.getBytes(StandardCharsets.UTF_8)) ++ .encodeToString(v.getBytes(UTF_8)) + .replace("+", "-") + .replace("/", "_"); + } +--- a/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/BasicAuthPushGatewayTest.java ++++ b/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/BasicAuthPushGatewayTest.java +@@ -12,7 +12,7 @@ import org.junit.jupiter.api.Test; + import org.mockserver.client.MockServerClient; + import org.mockserver.integration.ClientAndServer; + +-class BasicAuthPushGatewayTest { ++final class BasicAuthPushGatewayTest { + private MockServerClient mockServerClient; + + PrometheusRegistry registry; +@@ -20,7 +20,7 @@ class BasicAuthPushGatewayTest { + PushGateway pushGateway; + + @BeforeEach +- public void setUp() { ++ void setUp() { + mockServerClient = ClientAndServer.startClientAndServer(0); + registry = new PrometheusRegistry(); + gauge = Gauge.builder().name("g").help("help").build(); +@@ -39,7 +39,7 @@ class BasicAuthPushGatewayTest { + } + + @Test +- public void testAuthorizedPush() throws IOException { ++ void authorizedPush() throws IOException { + mockServerClient + .when( + request() +--- a/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/BearerTokenPushGatewayTest.java ++++ b/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/BearerTokenPushGatewayTest.java +@@ -12,7 +12,7 @@ import org.junit.jupiter.api.Test; + import org.mockserver.client.MockServerClient; + import org.mockserver.integration.ClientAndServer; + +-class BearerTokenPushGatewayTest { ++final class BearerTokenPushGatewayTest { + + private MockServerClient mockServerClient; + +@@ -21,7 +21,7 @@ class BearerTokenPushGatewayTest { + PushGateway pushGateway; + + @BeforeEach +- public void setUp() { ++ void setUp() { + mockServerClient = ClientAndServer.startClientAndServer(0); + registry = new PrometheusRegistry(); + gauge = Gauge.builder().name("g").help("help").build(); +@@ -40,7 +40,7 @@ class BearerTokenPushGatewayTest { + } + + @Test +- public void testAuthorizedPush() throws IOException { ++ void authorizedPush() throws IOException { + mockServerClient + .when( + request() +--- a/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/PushGatewayTest.java ++++ b/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/PushGatewayTest.java +@@ -2,6 +2,7 @@ package io.prometheus.metrics.exporter.pushgateway; + + import static org.assertj.core.api.Assertions.*; + import static org.assertj.core.api.Assertions.assertThat; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + import static org.mockserver.model.HttpRequest.request; + import static org.mockserver.model.HttpResponse.response; + +@@ -17,7 +18,7 @@ import org.junit.jupiter.api.Test; + import org.mockserver.client.MockServerClient; + import org.mockserver.integration.ClientAndServer; + +-class PushGatewayTest { ++final class PushGatewayTest { + + private MockServerClient mockServerClient; + +@@ -25,7 +26,7 @@ class PushGatewayTest { + Gauge gauge; + + @BeforeEach +- public void setUp() { ++ void setUp() { + mockServerClient = ClientAndServer.startClientAndServer(0); + registry = new PrometheusRegistry(); + gauge = Gauge.builder().name("g").help("help").build(); +@@ -37,7 +38,7 @@ class PushGatewayTest { + } + + @Test +- public void testInvalidURLThrowsRuntimeException() { ++ void invalidURLThrowsRuntimeException() { + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy( + () -> { +@@ -48,8 +49,7 @@ class PushGatewayTest { + } + + @Test +- public void testMultipleSlashesAreStrippedFromURL() +- throws NoSuchFieldException, IllegalAccessException { ++ void multipleSlashesAreStrippedFromURL() throws NoSuchFieldException, IllegalAccessException { + final PushGateway pushGateway = + PushGateway.builder().address("example.com:1234/context///path//").job("test").build(); + assertThat(getUrl(pushGateway)) +@@ -63,7 +63,7 @@ class PushGatewayTest { + } + + @Test +- public void testPush() throws IOException { ++ void push() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j")) + .respond(response().withStatusCode(202)); +@@ -77,7 +77,7 @@ class PushGatewayTest { + } + + @Test +- public void testPush200Response() throws IOException { ++ void push200Response() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j")) + .respond(response().withStatusCode(200)); +@@ -91,12 +91,11 @@ class PushGatewayTest { + } + + @Test +- public void testNon202ResponseThrows() { ++ void non202ResponseThrows() { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j")) + .respond(response().withStatusCode(500)); +- assertThatExceptionOfType(IOException.class) +- .isThrownBy( ++ assertThatThrownBy( + () -> { + PushGateway pg = + PushGateway.builder() +@@ -106,14 +105,14 @@ class PushGatewayTest { + .build(); + pg.push(); + }) +- .withMessageContaining( +- "Response code from http://localhost:" +- + mockServerClient.getPort() +- + "/metrics/job/j was 500"); ++ .isInstanceOf(IOException.class) ++ .hasMessageContaining( ++ "Response code from http://localhost:%s/metrics/job/j was 500", ++ mockServerClient.getPort()); + } + + @Test +- public void testPushCollector() throws IOException { ++ void pushCollector() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j")) + .respond(response().withStatusCode(202)); +@@ -127,7 +126,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushWithGroupingKey() throws IOException { ++ void pushWithGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j/l/v")) + .respond(response().withStatusCode(202)); +@@ -142,7 +141,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushWithMultiGroupingKey() throws IOException { ++ void pushWithMultiGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j/l/v/l2/v2")) + .respond(response().withStatusCode(202)); +@@ -158,7 +157,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushWithEmptyLabelGroupingKey() throws IOException { ++ void pushWithEmptyLabelGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j/l/v/l2@base64/=")) + .respond(response().withStatusCode(202)); +@@ -174,7 +173,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushWithGroupingKeyWithSlashes() throws IOException { ++ void pushWithGroupingKeyWithSlashes() throws IOException { + mockServerClient + .when( + request().withMethod("PUT").withPath("/metrics/job@base64/YS9i/l/v/l2@base64/75-_Lw==")) +@@ -191,7 +190,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushCollectorWithGroupingKey() throws IOException { ++ void pushCollectorWithGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("PUT").withPath("/metrics/job/j/l/v")) + .respond(response().withStatusCode(202)); +@@ -206,7 +205,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushAdd() throws IOException { ++ void pushAdd() throws IOException { + mockServerClient + .when(request().withMethod("POST").withPath("/metrics/job/j")) + .respond(response().withStatusCode(202)); +@@ -220,7 +219,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushAddCollector() throws IOException { ++ void pushAddCollector() throws IOException { + mockServerClient + .when(request().withMethod("POST").withPath("/metrics/job/j")) + .respond(response().withStatusCode(202)); +@@ -230,7 +229,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushAddWithGroupingKey() throws IOException { ++ void pushAddWithGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("POST").withPath("/metrics/job/j/l/v")) + .respond(response().withStatusCode(202)); +@@ -245,7 +244,7 @@ class PushGatewayTest { + } + + @Test +- public void testPushAddCollectorWithGroupingKey() throws IOException { ++ void pushAddCollectorWithGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("POST").withPath("/metrics/job/j/l/v")) + .respond(response().withStatusCode(202)); +@@ -260,7 +259,7 @@ class PushGatewayTest { + } + + @Test +- public void testDelete() throws IOException { ++ void delete() throws IOException { + mockServerClient + .when(request().withMethod("DELETE").withPath("/metrics/job/j")) + .respond(response().withStatusCode(202)); +@@ -270,7 +269,7 @@ class PushGatewayTest { + } + + @Test +- public void testDeleteWithGroupingKey() throws IOException { ++ void deleteWithGroupingKey() throws IOException { + mockServerClient + .when(request().withMethod("DELETE").withPath("/metrics/job/j/l/v")) + .respond(response().withStatusCode(202)); +@@ -284,7 +283,7 @@ class PushGatewayTest { + } + + @Test +- public void testInstanceIpGroupingKey() throws IOException { ++ void instanceIpGroupingKey() throws IOException { + String ip = InetAddress.getLocalHost().getHostAddress(); + assertThat(ip).isNotEmpty(); + mockServerClient +--- a/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/SchemeTest.java ++++ b/prometheus-metrics-exporter-pushgateway/src/test/java/io/prometheus/metrics/exporter/pushgateway/SchemeTest.java +@@ -1,18 +1,18 @@ + package io.prometheus.metrics.exporter.pushgateway; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import org.junit.jupiter.api.Test; + +-class SchemeTest { ++final class SchemeTest { + + @Test + void fromString() { + assertThat(Scheme.HTTP).hasToString("http"); + assertThat(Scheme.HTTPS).hasToString("https"); +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> Scheme.fromString("ftp")) +- .withMessage("ftp: Unsupported scheme. Expecting 'http' or 'https'."); ++ assertThatThrownBy(() -> Scheme.fromString("ftp")) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessage("ftp: Unsupported scheme. Expecting 'http' or 'https'."); + } + } +--- a/prometheus-metrics-exposition-formats/src/test/java/io/prometheus/metrics/expositionformats/ExpositionFormatsTest.java ++++ b/prometheus-metrics-exposition-formats/src/test/java/io/prometheus/metrics/expositionformats/ExpositionFormatsTest.java +@@ -30,7 +30,7 @@ import java.io.ByteArrayOutputStream; + import java.io.IOException; + import org.junit.jupiter.api.Test; + +-class ExpositionFormatsTest { ++final class ExpositionFormatsTest { + + private final String exemplar1String = + "{env=\"prod\",span_id=\"12345\",trace_id=\"abcde\"} 1.7 1672850685.829"; +@@ -107,7 +107,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testCounterComplete() throws IOException { ++ void counterComplete() throws IOException { + String openMetricsText = + "# TYPE service_time_seconds counter\n" + + "# UNIT service_time_seconds seconds\n" +@@ -235,7 +235,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testCounterMinimal() throws IOException { ++ void counterMinimal() throws IOException { + String openMetricsText = "# TYPE my_counter counter\n" + "my_counter_total 1.1\n" + "# EOF\n"; + String prometheusText = "# TYPE my_counter_total counter\n" + "my_counter_total 1.1\n"; + String prometheusProtobuf = +@@ -253,7 +253,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testCounterWithDots() throws IOException { ++ void counterWithDots() throws IOException { + String openMetricsText = + "# TYPE my_request_count counter\n" + + "my_request_count_total{http_path=\"/hello\"} 3.0 # " +@@ -293,7 +293,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testGaugeComplete() throws IOException { ++ void gaugeComplete() throws IOException { + String openMetricsText = + "# TYPE disk_usage_ratio gauge\n" + + "# UNIT disk_usage_ratio ratio\n" +@@ -374,7 +374,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testGaugeMinimal() throws IOException { ++ void gaugeMinimal() throws IOException { + String openMetricsText = + "# TYPE temperature_centigrade gauge\n" + "temperature_centigrade 22.3\n" + "# EOF\n"; + String prometheusText = +@@ -394,7 +394,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testGaugeWithDots() throws IOException { ++ void gaugeWithDots() throws IOException { + String openMetricsText = + "# TYPE my_temperature_celsius gauge\n" + + "# UNIT my_temperature_celsius celsius\n" +@@ -446,7 +446,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryComplete() throws IOException { ++ void summaryComplete() throws IOException { + String openMetricsText = + "# TYPE http_request_duration_seconds summary\n" + + "# UNIT http_request_duration_seconds seconds\n" +@@ -739,7 +739,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryWithoutQuantiles() throws IOException { ++ void summaryWithoutQuantiles() throws IOException { + String openMetricsText = + "# TYPE latency_seconds summary\n" + + "# UNIT latency_seconds seconds\n" +@@ -779,7 +779,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryNoCountAndSum() throws IOException { ++ void summaryNoCountAndSum() throws IOException { + String openMetricsText = + "# TYPE latency_seconds summary\n" + + "latency_seconds{quantile=\"0.95\"} 200.0\n" +@@ -812,7 +812,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryJustCount() throws IOException { ++ void summaryJustCount() throws IOException { + String openMetricsText = + "# TYPE latency_seconds summary\n" + "latency_seconds_count 1\n" + "# EOF\n"; + String prometheusText = "# TYPE latency_seconds summary\n" + "latency_seconds_count 1\n"; +@@ -839,7 +839,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryJustSum() throws IOException { ++ void summaryJustSum() throws IOException { + String openMetricsText = + "# TYPE latency_seconds summary\n" + "latency_seconds_sum 12.3\n" + "# EOF\n"; + String prometheusText = "# TYPE latency_seconds summary\n" + "latency_seconds_sum 12.3\n"; +@@ -866,7 +866,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryEmptyData() throws IOException { ++ void summaryEmptyData() throws IOException { + // SummaryData can be present but empty (no count, no sum, no quantiles). + // This should be treated like no data is present. + SummarySnapshot summary = +@@ -884,7 +884,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryEmptyAndNonEmpty() throws IOException { ++ void summaryEmptyAndNonEmpty() throws IOException { + String openMetricsText = + "# TYPE latency_seconds summary\n" + + "latency_seconds_count{path=\"/v2\"} 2\n" +@@ -926,7 +926,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testSummaryWithDots() throws IOException { ++ void summaryWithDots() throws IOException { + String openMetricsText = + "# TYPE my_request_duration_seconds summary\n" + + "# UNIT my_request_duration_seconds seconds\n" +@@ -980,7 +980,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicHistogramComplete() throws Exception { ++ void classicHistogramComplete() throws Exception { + String openMetricsText = + "# TYPE response_size_bytes histogram\n" + + "# UNIT response_size_bytes bytes\n" +@@ -1286,7 +1286,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicHistogramMinimal() throws Exception { ++ void classicHistogramMinimal() throws Exception { + // In OpenMetrics a histogram can have a _count if and only if it has a _sum. + // In Prometheus format, a histogram can have a _count without a _sum. + String openMetricsText = +@@ -1330,7 +1330,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicHistogramCountAndSum() throws Exception { ++ void classicHistogramCountAndSum() throws Exception { + String openMetricsText = + "# TYPE request_latency_seconds histogram\n" + + "request_latency_seconds_bucket{le=\"+Inf\"} 2\n" +@@ -1377,7 +1377,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicGaugeHistogramComplete() throws IOException { ++ void classicGaugeHistogramComplete() throws IOException { + String openMetricsText = + "# TYPE cache_size_bytes gaugehistogram\n" + + "# UNIT cache_size_bytes bytes\n" +@@ -1673,7 +1673,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicGaugeHistogramMinimal() throws IOException { ++ void classicGaugeHistogramMinimal() throws IOException { + // In OpenMetrics a histogram can have a _count if and only if it has a _sum. + // In Prometheus format, a histogram can have a _count without a _sum. + String openMetricsText = +@@ -1719,7 +1719,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicGaugeHistogramCountAndSum() throws IOException { ++ void classicGaugeHistogramCountAndSum() throws IOException { + String openMetricsText = + "# TYPE queue_size_bytes gaugehistogram\n" + + "queue_size_bytes_bucket{le=\"+Inf\"} 130\n" +@@ -1769,7 +1769,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testClassicHistogramWithDots() throws IOException { ++ void classicHistogramWithDots() throws IOException { + String openMetricsText = + "# TYPE my_request_duration_seconds histogram\n" + + "# UNIT my_request_duration_seconds seconds\n" +@@ -1839,7 +1839,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testNativeHistogramComplete() throws IOException { ++ void nativeHistogramComplete() throws IOException { + String openMetricsText = + "# TYPE response_size_bytes histogram\n" + + "# UNIT response_size_bytes bytes\n" +@@ -2150,7 +2150,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testNativeHistogramMinimal() throws IOException { ++ void nativeHistogramMinimal() throws IOException { + String openMetricsText = + "# TYPE latency_seconds histogram\n" + + "latency_seconds_bucket{le=\"+Inf\"} 0\n" +@@ -2184,7 +2184,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testNativeHistogramWithDots() throws IOException { ++ void nativeHistogramWithDots() throws IOException { + String openMetricsText = + "# TYPE my_request_duration_seconds histogram\n" + + "# UNIT my_request_duration_seconds seconds\n" +@@ -2261,7 +2261,7 @@ class ExpositionFormatsTest { + // TODO: Gauge Native Histogram + + @Test +- public void testInfo() throws IOException { ++ void info() throws IOException { + String openMetrics = + "# TYPE version info\n" + + "# HELP version version information\n" +@@ -2287,7 +2287,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testInfoWithDots() throws IOException { ++ void infoWithDots() throws IOException { + String openMetricsText = + "# TYPE jvm_status info\n" + + "# HELP jvm_status JVM status info\n" +@@ -2322,7 +2322,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testStateSetComplete() throws IOException { ++ void stateSetComplete() throws IOException { + String openMetrics = + "# TYPE state stateset\n" + + "# HELP state complete state set example\n" +@@ -2380,7 +2380,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testStateSetMinimal() throws IOException { ++ void stateSetMinimal() throws IOException { + String openMetrics = + "# TYPE state stateset\n" + + "state{state=\"a\"} 1\n" +@@ -2404,7 +2404,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testStateSetWithDots() throws IOException { ++ void stateSetWithDots() throws IOException { + String openMetricsText = + "# TYPE my_application_state stateset\n" + + "# HELP my_application_state My application state\n" +@@ -2448,7 +2448,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testUnknownComplete() throws IOException { ++ void unknownComplete() throws IOException { + String openMetrics = + "# TYPE my_special_thing_bytes unknown\n" + + "# UNIT my_special_thing_bytes bytes\n" +@@ -2513,7 +2513,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testUnknownMinimal() throws IOException { ++ void unknownMinimal() throws IOException { + String openMetrics = "# TYPE other unknown\n" + "other 22.3\n" + "# EOF\n"; + String prometheus = "# TYPE other untyped\n" + "other 22.3\n"; + UnknownSnapshot unknown = +@@ -2528,7 +2528,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testUnknownWithDots() throws IOException { ++ void unknownWithDots() throws IOException { + String openMetrics = + "# TYPE some_unknown_metric_bytes unknown\n" + + "# UNIT some_unknown_metric_bytes bytes\n" +@@ -2577,7 +2577,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testHelpEscape() throws IOException { ++ void helpEscape() throws IOException { + String openMetrics = + "# TYPE test counter\n" + + "# HELP test Some text and \\n some \\\" escaping\n" +@@ -2600,7 +2600,7 @@ class ExpositionFormatsTest { + } + + @Test +- public void testLabelValueEscape() throws IOException { ++ void labelValueEscape() throws IOException { + String openMetrics = + "# TYPE test counter\n" + + "test_total{a=\"x\",b=\"escaping\\\" example \\n \"} 1.0\n" +--- a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java ++++ b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java +@@ -5,7 +5,9 @@ import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeEscape + import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLabels; + import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLong; + import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeTimestamp; ++import static java.nio.charset.StandardCharsets.UTF_8; + ++import com.google.common.base.Strings; + import io.prometheus.metrics.model.snapshots.ClassicHistogramBuckets; + import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import io.prometheus.metrics.model.snapshots.DataPointSnapshot; +@@ -26,7 +28,6 @@ import io.prometheus.metrics.model.snapshots.UnknownSnapshot; + import java.io.IOException; + import java.io.OutputStream; + import java.io.OutputStreamWriter; +-import java.nio.charset.StandardCharsets; + import java.util.List; + + /** +@@ -65,7 +66,7 @@ public class OpenMetricsTextFormatWriter implements ExpositionFormatWriter { + + @Override + public void write(OutputStream out, MetricSnapshots metricSnapshots) throws IOException { +- OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); ++ OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8); + for (MetricSnapshot snapshot : metricSnapshots) { + if (!snapshot.getDataPoints().isEmpty()) { + if (snapshot instanceof CounterSnapshot) { +@@ -368,7 +369,7 @@ public class OpenMetricsTextFormatWriter implements ExpositionFormatWriter { + writeEscapedLabelValue(writer, metadata.getUnit().toString()); + writer.write('\n'); + } +- if (metadata.getHelp() != null && !metadata.getHelp().isEmpty()) { ++ if (!Strings.isNullOrEmpty(metadata.getHelp())) { + writer.write("# HELP "); + writer.write(metadata.getPrometheusName()); + writer.write(' '); +--- a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/PrometheusTextFormatWriter.java ++++ b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/PrometheusTextFormatWriter.java +@@ -5,7 +5,9 @@ import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeEscape + import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLabels; + import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLong; + import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeTimestamp; ++import static java.nio.charset.StandardCharsets.UTF_8; + ++import com.google.common.base.Strings; + import io.prometheus.metrics.model.snapshots.ClassicHistogramBuckets; + import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import io.prometheus.metrics.model.snapshots.DataPointSnapshot; +@@ -24,7 +26,6 @@ import java.io.IOException; + import java.io.OutputStream; + import java.io.OutputStreamWriter; + import java.io.Writer; +-import java.nio.charset.StandardCharsets; + + /** + * Write the Prometheus text format. This is the default if you view a Prometheus endpoint with your +@@ -59,9 +60,9 @@ public class PrometheusTextFormatWriter implements ExpositionFormatWriter { + // See https://prometheus.io/docs/instrumenting/exposition_formats/ + // "unknown", "gauge", "counter", "stateset", "info", "histogram", "gaugehistogram", and + // "summary". +- OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); ++ OutputStreamWriter writer = new OutputStreamWriter(out, UTF_8); + for (MetricSnapshot snapshot : metricSnapshots) { +- if (snapshot.getDataPoints().size() > 0) { ++ if (!snapshot.getDataPoints().isEmpty()) { + if (snapshot instanceof CounterSnapshot) { + writeCounter(writer, (CounterSnapshot) snapshot); + } else if (snapshot instanceof GaugeSnapshot) { +@@ -81,7 +82,7 @@ public class PrometheusTextFormatWriter implements ExpositionFormatWriter { + } + if (writeCreatedTimestamps) { + for (MetricSnapshot snapshot : metricSnapshots) { +- if (snapshot.getDataPoints().size() > 0) { ++ if (!snapshot.getDataPoints().isEmpty()) { + if (snapshot instanceof CounterSnapshot) { + writeCreated(writer, snapshot); + } else if (snapshot instanceof HistogramSnapshot) { +@@ -113,7 +114,7 @@ public class PrometheusTextFormatWriter implements ExpositionFormatWriter { + + private void writeCounter(OutputStreamWriter writer, CounterSnapshot snapshot) + throws IOException { +- if (snapshot.getDataPoints().size() > 0) { ++ if (!snapshot.getDataPoints().isEmpty()) { + MetricMetadata metadata = snapshot.getMetadata(); + writeMetadata(writer, "_total", "counter", metadata); + for (CounterSnapshot.CounterDataPointSnapshot data : snapshot.getDataPoints()) { +@@ -329,7 +330,7 @@ public class PrometheusTextFormatWriter implements ExpositionFormatWriter { + private void writeMetadata( + OutputStreamWriter writer, String suffix, String typeString, MetricMetadata metadata) + throws IOException { +- if (metadata.getHelp() != null && !metadata.getHelp().isEmpty()) { ++ if (!Strings.isNullOrEmpty(metadata.getHelp())) { + writer.write("# HELP "); + writer.write(metadata.getPrometheusName()); + if (suffix != null) { +--- a/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java ++++ b/prometheus-metrics-instrumentation-caffeine/src/main/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollector.java +@@ -1,9 +1,12 @@ + package io.prometheus.metrics.instrumentation.caffeine; + ++import static java.util.Collections.unmodifiableList; ++ + import com.github.benmanes.caffeine.cache.AsyncCache; + import com.github.benmanes.caffeine.cache.Cache; + import com.github.benmanes.caffeine.cache.LoadingCache; + import com.github.benmanes.caffeine.cache.stats.CacheStats; ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.model.registry.MultiCollector; + import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +@@ -11,7 +14,6 @@ import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; + import java.util.Arrays; +-import java.util.Collections; + import java.util.List; + import java.util.Map; + import java.util.concurrent.ConcurrentHashMap; +@@ -67,7 +69,7 @@ public class CacheMetricsCollector implements MultiCollector { + "caffeine_cache_load_duration_seconds"; + + private static final List ALL_METRIC_NAMES = +- Collections.unmodifiableList( ++ unmodifiableList( + Arrays.asList( + METRIC_NAME_CACHE_HIT, + METRIC_NAME_CACHE_MISS, +@@ -168,7 +170,7 @@ public class CacheMetricsCollector implements MultiCollector { + .help("Cache load duration: both success and failures"); + + for (final Map.Entry> c : children.entrySet()) { +- final List cacheName = Collections.singletonList(c.getKey()); ++ final List cacheName = ImmutableList.of(c.getKey()); + final Labels labels = Labels.of(labelNames, cacheName); + + final CacheStats stats = c.getValue().stats(); +--- a/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java ++++ b/prometheus-metrics-instrumentation-caffeine/src/test/java/io/prometheus/metrics/instrumentation/caffeine/CacheMetricsCollectorTest.java +@@ -24,10 +24,10 @@ import java.util.List; + import org.junit.jupiter.api.Test; + + @SuppressWarnings("CheckReturnValue") +-class CacheMetricsCollectorTest { ++final class CacheMetricsCollectorTest { + + @Test +- public void cacheExposesMetricsForHitMissAndEviction() { ++ void cacheExposesMetricsForHitMissAndEviction() { + // Run cleanup in same thread, to remove async behavior with evictions + final Cache cache = + Caffeine.newBuilder().maximumSize(2).recordStats().executor(Runnable::run).build(); +@@ -79,8 +79,8 @@ class CacheMetricsCollectorTest { + + @SuppressWarnings("unchecked") + @Test +- public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception { +- final CacheLoader loader = mock(CacheLoader.class); ++ void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception { ++ final CacheLoader loader = mock(); + when(loader.load(anyString())) + .thenReturn("First User") + .thenThrow(new RuntimeException("Seconds time fails")) +@@ -114,11 +114,11 @@ class CacheMetricsCollectorTest { + getDataPointSnapshot(registry, "caffeine_cache_load_duration_seconds", "loadingusers"); + + assertThat(loadDuration.getCount()).isEqualTo(3); +- assertThat(loadDuration.getSum()).isGreaterThan(0); ++ assertThat(loadDuration.getSum()).isPositive(); + } + + @Test +- public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() { ++ void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() { + final CacheMetricsCollector collector = new CacheMetricsCollector(); + + final PrometheusRegistry registry = new PrometheusRegistry(); +@@ -131,7 +131,7 @@ class CacheMetricsCollectorTest { + } + + @Test +- public void collectedMetricNamesAreKnownPrometheusNames() { ++ void collectedMetricNamesAreKnownPrometheusNames() { + final CacheMetricsCollector collector = new CacheMetricsCollector(); + + final PrometheusRegistry registry = new PrometheusRegistry(); +--- a/prometheus-metrics-instrumentation-dropwizard/src/main/java/io/prometheus/metrics/instrumentation/dropwizard/DropwizardExports.java ++++ b/prometheus-metrics-instrumentation-dropwizard/src/main/java/io/prometheus/metrics/instrumentation/dropwizard/DropwizardExports.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.instrumentation.dropwizard; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import com.codahale.metrics.Counter; + import com.codahale.metrics.Gauge; + import com.codahale.metrics.Histogram; +@@ -9,6 +11,7 @@ import com.codahale.metrics.MetricFilter; + import com.codahale.metrics.MetricRegistry; + import com.codahale.metrics.Snapshot; + import com.codahale.metrics.Timer; ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.instrumentation.dropwizard5.labels.CustomLabelMapper; + import io.prometheus.metrics.model.registry.MultiCollector; + import io.prometheus.metrics.model.registry.PrometheusRegistry; +@@ -20,7 +23,6 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import io.prometheus.metrics.model.snapshots.PrometheusNaming; + import io.prometheus.metrics.model.snapshots.Quantiles; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; +-import java.util.Collections; + import java.util.Optional; + import java.util.concurrent.TimeUnit; + import java.util.logging.Level; +@@ -28,7 +30,7 @@ import java.util.logging.Logger; + + /** Collect Dropwizard metrics from a MetricRegistry. */ + public class DropwizardExports implements MultiCollector { +- private static final Logger logger = Logger.getLogger(DropwizardExports.class.getName()); ++ private static final Logger LOGGER = Logger.getLogger(DropwizardExports.class.getName()); + private final MetricRegistry registry; + private final MetricFilter metricFilter; + private final Optional labelMapper; +@@ -76,7 +78,8 @@ public class DropwizardExports implements MultiCollector { + } + + private MetricMetadata getMetricMetaData(String metricName, Metric metric) { +- String name = labelMapper.isPresent() ? labelMapper.get().getName(metricName) : metricName; ++ String name = ++ labelMapper.isPresent() ? labelMapper.orElseThrow().getName(metricName) : metricName; + return new MetricMetadata( + PrometheusNaming.sanitizeMetricName(name), getHelpMessage(metricName, metric)); + } +@@ -93,9 +96,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new CounterSnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + /** Export gauge as a prometheus gauge. */ +@@ -107,7 +109,7 @@ public class DropwizardExports implements MultiCollector { + } else if (obj instanceof Boolean) { + value = ((Boolean) obj) ? 1 : 0; + } else { +- logger.log( ++ LOGGER.log( + Level.FINE, + String.format( + "Invalid type for Gauge %s: %s", +@@ -121,9 +123,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new GaugeSnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new GaugeSnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + /** +@@ -153,9 +154,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new SummarySnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new SummarySnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + /** Convert histogram snapshot. */ +@@ -186,9 +186,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new CounterSnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + @Override +@@ -252,9 +251,7 @@ public class DropwizardExports implements MultiCollector { + } + + DropwizardExports build() { +- if (registry == null) { +- throw new IllegalArgumentException("MetricRegistry must be set"); +- } ++ checkArgument(registry != null, "MetricRegistry must be set"); + if (labelMapper == null) { + return new DropwizardExports(registry, metricFilter); + } else { +--- a/prometheus-metrics-instrumentation-dropwizard/src/test/java/io/prometheus/metrics/instrumentation/dropwizard/DropwizardExportsTest.java ++++ b/prometheus-metrics-instrumentation-dropwizard/src/test/java/io/prometheus/metrics/instrumentation/dropwizard/DropwizardExportsTest.java +@@ -1,5 +1,6 @@ + package io.prometheus.metrics.instrumentation.dropwizard; + ++import static java.nio.charset.StandardCharsets.UTF_8; + import static org.assertj.core.api.Assertions.assertThat; + import static org.assertj.core.api.Assertions.assertThatCode; + import static org.assertj.core.api.Assertions.assertThatThrownBy; +@@ -10,18 +11,17 @@ import io.prometheus.metrics.model.registry.PrometheusRegistry; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; + import java.io.ByteArrayOutputStream; + import java.io.IOException; +-import java.nio.charset.StandardCharsets; + import java.util.concurrent.TimeUnit; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class DropwizardExportsTest { ++final class DropwizardExportsTest { + + private final PrometheusRegistry registry = new PrometheusRegistry(); + private MetricRegistry metricRegistry; + + @BeforeEach +- public void setUp() { ++ void setUp() { + metricRegistry = new MetricRegistry(); + DropwizardExports.builder() + .dropwizardRegistry(metricRegistry) +@@ -30,21 +30,21 @@ class DropwizardExportsTest { + } + + @Test +- public void testBuilderThrowsErrorOnNullRegistry() { ++ void builderThrowsErrorOnNullRegistry() { + assertThatThrownBy( + () -> DropwizardExports.builder().dropwizardRegistry(null).register(registry)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void testBuilderCreatesOkay() { ++ void builderCreatesOkay() { + assertThatCode( + () -> DropwizardExports.builder().dropwizardRegistry(metricRegistry).register(registry)) + .doesNotThrowAnyException(); + } + + @Test +- public void testCounter() { ++ void counter() { + metricRegistry.counter("foo.bar").inc(1); + String expected = + """ +@@ -58,7 +58,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testGauge() { ++ void gauge() { + // don't convert to lambda, as we need to test the type + Gauge integerGauge = + new Gauge() { +@@ -126,7 +126,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testInvalidGaugeType() { ++ void invalidGaugeType() { + Gauge invalidGauge = () -> "foobar"; + + metricRegistry.register("invalid_gauge", invalidGauge); +@@ -136,7 +136,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testGaugeReturningNullValue() { ++ void gaugeReturningNullValue() { + Gauge invalidGauge = () -> null; + metricRegistry.register("invalid_gauge", invalidGauge); + String expected = "# EOF\n"; +@@ -144,7 +144,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testHistogram() { ++ void histogram() { + // just test the standard mapper + final MetricRegistry metricRegistry = new MetricRegistry(); + PrometheusRegistry pmRegistry = new PrometheusRegistry(); +@@ -197,7 +197,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testMeter() { ++ void meter() { + Meter meter = metricRegistry.meter("meter"); + meter.mark(); + meter.mark(); +@@ -213,7 +213,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testTimer() throws InterruptedException { ++ void timer() throws InterruptedException { + final MetricRegistry metricRegistry = new MetricRegistry(); + DropwizardExports exports = new DropwizardExports(metricRegistry); + Timer t = metricRegistry.timer("timer"); +@@ -232,12 +232,12 @@ class DropwizardExportsTest { + dataPointSnapshot + .getQuantiles() + .forEach(i -> assertThat(i.getValue()).isGreaterThan(timeSpentMillis / 1000d)); +- assertThat(dataPointSnapshot.getCount()).isOne(); ++ assertThat(dataPointSnapshot.getCount()).isEqualTo(1); + }); + } + + @Test +- public void testThatMetricHelpUsesOriginalDropwizardName() { ++ void thatMetricHelpUsesOriginalDropwizardName() { + metricRegistry.timer("my.application.namedTimer1"); + metricRegistry.counter("my.application.namedCounter1"); + metricRegistry.meter("my.application.namedMeter1"); +@@ -290,7 +290,7 @@ class DropwizardExportsTest { + OpenMetricsTextFormatWriter writer = new OpenMetricsTextFormatWriter(true, true); + try { + writer.write(out, _registry.scrape()); +- return out.toString(StandardCharsets.UTF_8); ++ return out.toString(UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } +--- a/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/DropwizardExports.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/DropwizardExports.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.instrumentation.dropwizard5; + ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import com.google.common.collect.ImmutableList; + import io.dropwizard.metrics5.Counter; + import io.dropwizard.metrics5.Gauge; + import io.dropwizard.metrics5.Histogram; +@@ -21,7 +24,6 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import io.prometheus.metrics.model.snapshots.PrometheusNaming; + import io.prometheus.metrics.model.snapshots.Quantiles; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; +-import java.util.Collections; + import java.util.Map; + import java.util.Optional; + import java.util.concurrent.TimeUnit; +@@ -30,7 +32,7 @@ import java.util.logging.Logger; + + /** Collect Dropwizard metrics from a MetricRegistry. */ + public class DropwizardExports implements MultiCollector { +- private static final Logger logger = Logger.getLogger(DropwizardExports.class.getName()); ++ private static final Logger LOGGER = Logger.getLogger(DropwizardExports.class.getName()); + private final MetricRegistry registry; + private final MetricFilter metricFilter; + private final Optional labelMapper; +@@ -78,7 +80,8 @@ public class DropwizardExports implements MultiCollector { + } + + private MetricMetadata getMetricMetaData(String metricName, Metric metric) { +- String name = labelMapper.isPresent() ? labelMapper.get().getName(metricName) : metricName; ++ String name = ++ labelMapper.isPresent() ? labelMapper.orElseThrow().getName(metricName) : metricName; + return new MetricMetadata( + PrometheusNaming.sanitizeMetricName(name), getHelpMessage(metricName, metric)); + } +@@ -95,9 +98,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new CounterSnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + /** Export gauge as a prometheus gauge. */ +@@ -109,7 +111,7 @@ public class DropwizardExports implements MultiCollector { + } else if (obj instanceof Boolean) { + value = ((Boolean) obj) ? 1 : 0; + } else { +- logger.log( ++ LOGGER.log( + Level.FINE, + String.format( + "Invalid type for Gauge %s: %s", +@@ -123,9 +125,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new GaugeSnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new GaugeSnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + /** +@@ -155,9 +156,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new SummarySnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new SummarySnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + /** Convert histogram snapshot. */ +@@ -188,9 +188,8 @@ public class DropwizardExports implements MultiCollector { + labelMapper.ifPresent( + mapper -> + dataPointBuilder.labels( +- mapper.getLabels( +- dropwizardName, Collections.emptyList(), Collections.emptyList()))); +- return new CounterSnapshot(metadata, Collections.singletonList(dataPointBuilder.build())); ++ mapper.getLabels(dropwizardName, ImmutableList.of(), ImmutableList.of()))); ++ return new CounterSnapshot(metadata, ImmutableList.of(dataPointBuilder.build())); + } + + @Override +@@ -246,9 +245,7 @@ public class DropwizardExports implements MultiCollector { + } + + DropwizardExports build() { +- if (registry == null) { +- throw new IllegalArgumentException("MetricRegistry must be set"); +- } ++ checkArgument(registry != null, "MetricRegistry must be set"); + if (labelMapper == null) { + return new DropwizardExports(registry, metricFilter); + } else { +--- a/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/CustomLabelMapper.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/CustomLabelMapper.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.instrumentation.dropwizard5.labels; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import io.prometheus.metrics.model.snapshots.Labels; + import java.util.ArrayList; + import java.util.List; +@@ -14,9 +16,9 @@ public class CustomLabelMapper { + private final List compiledMapperConfigs; + + public CustomLabelMapper(final List mapperConfigs) { +- if (mapperConfigs == null || mapperConfigs.isEmpty()) { +- throw new IllegalArgumentException("CustomLabelMapper needs some mapper configs!"); +- } ++ checkArgument( ++ mapperConfigs != null && !mapperConfigs.isEmpty(), ++ "CustomLabelMapper needs some mapper configs!"); + + this.compiledMapperConfigs = new ArrayList(mapperConfigs.size()); + for (MapperConfig config : mapperConfigs) { +@@ -25,9 +27,7 @@ public class CustomLabelMapper { + } + + public String getName(final String dropwizardName) { +- if (dropwizardName == null) { +- throw new IllegalArgumentException("Dropwizard metric name cannot be null"); +- } ++ checkArgument(dropwizardName != null, "Dropwizard metric name cannot be null"); + + CompiledMapperConfig matchingConfig = null; + for (CompiledMapperConfig config : this.compiledMapperConfigs) { +@@ -50,9 +50,7 @@ public class CustomLabelMapper { + final String dropwizardName, + final List additionalLabelNames, + final List additionalLabelValues) { +- if (dropwizardName == null) { +- throw new IllegalArgumentException("Dropwizard metric name cannot be null"); +- } ++ checkArgument(dropwizardName != null, "Dropwizard metric name cannot be null"); + + CompiledMapperConfig matchingConfig = null; + for (CompiledMapperConfig config : this.compiledMapperConfigs) { +--- a/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/GraphiteNamePattern.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/GraphiteNamePattern.java +@@ -1,5 +1,6 @@ + package io.prometheus.metrics.instrumentation.dropwizard5.labels; + ++import static com.google.common.base.Preconditions.checkArgument; + import static io.prometheus.metrics.instrumentation.dropwizard5.labels.MapperConfig.METRIC_GLOB_REGEX; + + import java.util.HashMap; +@@ -32,10 +33,9 @@ class GraphiteNamePattern { + * @param pattern The glob style pattern to be used. + */ + GraphiteNamePattern(final String pattern) throws IllegalArgumentException { +- if (!VALIDATION_PATTERN.matcher(pattern).matches()) { +- throw new IllegalArgumentException( +- String.format("Provided pattern [%s] does not matches [%s]", pattern, METRIC_GLOB_REGEX)); +- } ++ checkArgument( ++ VALIDATION_PATTERN.matcher(pattern).matches(), ++ String.format("Provided pattern [%s] does not matches [%s]", pattern, METRIC_GLOB_REGEX)); + initializePattern(pattern); + } + +@@ -84,7 +84,7 @@ class GraphiteNamePattern { + escapedPattern.append("([^.]*)").append(quoted); + } + +- final String regex = "^" + escapedPattern.toString() + "$"; ++ final String regex = "^" + escapedPattern + "$"; + this.patternStr = regex; + this.pattern = Pattern.compile(regex); + } +--- a/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/MapperConfig.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/main/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/MapperConfig.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.instrumentation.dropwizard5.labels; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.HashMap; + import java.util.Map; + import java.util.regex.Pattern; +@@ -106,21 +108,19 @@ public final class MapperConfig { + } + + private void validateMatch(final String match) { +- if (!MATCH_EXPRESSION_PATTERN.matcher(match).matches()) { +- throw new IllegalArgumentException( +- String.format( +- "Match expression [%s] does not match required pattern %s", +- match, MATCH_EXPRESSION_PATTERN)); +- } ++ checkArgument( ++ MATCH_EXPRESSION_PATTERN.matcher(match).matches(), ++ String.format( ++ "Match expression [%s] does not match required pattern %s", ++ match, MATCH_EXPRESSION_PATTERN)); + } + + private void validateLabels(final Map labels) { + if (labels != null) { + for (final String key : labels.keySet()) { +- if (!LABEL_PATTERN.matcher(key).matches()) { +- throw new IllegalArgumentException( +- String.format("Label [%s] does not match required pattern %s", match, LABEL_PATTERN)); +- } ++ checkArgument( ++ LABEL_PATTERN.matcher(key).matches(), ++ String.format("Label [%s] does not match required pattern %s", match, LABEL_PATTERN)); + } + } + } +@@ -149,7 +149,6 @@ public final class MapperConfig { + public int hashCode() { + int result = match != null ? match.hashCode() : 0; + result = 31 * result + (name != null ? name.hashCode() : 0); +- result = 31 * result + (labels != null ? labels.hashCode() : 0); +- return result; ++ return 31 * result + (labels != null ? labels.hashCode() : 0); + } + } +--- a/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/DropwizardExportsTest.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/DropwizardExportsTest.java +@@ -16,19 +16,19 @@ import java.util.concurrent.TimeUnit; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class DropwizardExportsTest { ++final class DropwizardExportsTest { + + private PrometheusRegistry registry = new PrometheusRegistry(); + private MetricRegistry metricRegistry; + + @BeforeEach +- public void setUp() { ++ void setUp() { + metricRegistry = new MetricRegistry(); + DropwizardExports.builder().dropwizardRegistry(metricRegistry).register(registry); + } + + @Test +- public void testCounter() { ++ void counter() { + metricRegistry.counter("foo.bar").inc(1); + String expected = + "# TYPE foo_bar counter\n" +@@ -40,7 +40,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testGauge() { ++ void gauge() { + // don't convert to lambda, as we need to test the type + Gauge integerGauge = + new Gauge() { +@@ -106,7 +106,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testInvalidGaugeType() { ++ void invalidGaugeType() { + Gauge invalidGauge = () -> "foobar"; + + metricRegistry.register("invalid_gauge", invalidGauge); +@@ -116,7 +116,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testGaugeReturningNullValue() { ++ void gaugeReturningNullValue() { + Gauge invalidGauge = () -> null; + metricRegistry.register("invalid_gauge", invalidGauge); + String expected = "# EOF\n"; +@@ -124,7 +124,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testHistogram() { ++ void histogram() { + // just test the standard mapper + final MetricRegistry metricRegistry = new MetricRegistry(); + PrometheusRegistry pmRegistry = new PrometheusRegistry(); +@@ -169,13 +169,13 @@ class DropwizardExportsTest { + // The following asserts the values, but allows an error of 1.0 for quantile values. + + MetricSnapshots snapshots = pmRegistry.scrape(name -> name.equals("hist")); +- assertThat(snapshots.size()).isOne(); ++ assertThat(snapshots.size()).isEqualTo(1); + SummarySnapshot snapshot = (SummarySnapshot) snapshots.get(0); + assertThat(snapshot.getMetadata().getName()).isEqualTo("hist"); + assertThat(snapshot.getMetadata().getHelp()) + .isEqualTo( + "Generated from Dropwizard metric import (metric=hist, type=io.dropwizard.metrics5.Histogram)"); +- assertThat(snapshot.getDataPoints().size()).isOne(); ++ assertThat(snapshot.getDataPoints()).hasSize(1); + SummarySnapshot.SummaryDataPointSnapshot dataPoint = snapshot.getDataPoints().get(0); + assertThat(dataPoint.hasCount()).isTrue(); + assertThat(dataPoint.getCount()).isEqualTo(100); +@@ -197,7 +197,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testMeter() { ++ void meter() { + Meter meter = metricRegistry.meter("meter"); + meter.mark(); + meter.mark(); +@@ -211,7 +211,7 @@ class DropwizardExportsTest { + } + + @Test +- public void testTimer() throws InterruptedException { ++ void timer() throws InterruptedException { + final MetricRegistry metricRegistry = new MetricRegistry(); + DropwizardExports exports = new DropwizardExports(metricRegistry); + Timer t = metricRegistry.timer("timer"); +@@ -233,11 +233,11 @@ class DropwizardExportsTest { + System.out.println(i.getQuantile() + " : " + i.getValue()); + assertThat(i.getValue()).isGreaterThan(timeSpentMillis / 1000d); + }); +- assertThat(dataPointSnapshot.getCount()).isOne(); ++ assertThat(dataPointSnapshot.getCount()).isEqualTo(1); + } + + @Test +- public void testThatMetricHelpUsesOriginalDropwizardName() { ++ void thatMetricHelpUsesOriginalDropwizardName() { + + metricRegistry.timer("my.application.namedTimer1"); + metricRegistry.counter("my.application.namedCounter1"); +--- a/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/CustomLabelMapperTest.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/CustomLabelMapperTest.java +@@ -1,8 +1,9 @@ + package io.prometheus.metrics.instrumentation.dropwizard5.labels; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + ++import com.google.common.collect.ImmutableList; + import io.dropwizard.metrics5.MetricFilter; + import io.dropwizard.metrics5.MetricRegistry; + import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter; +@@ -15,22 +16,22 @@ import java.util.*; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class CustomLabelMapperTest { ++final class CustomLabelMapperTest { + private MetricRegistry metricRegistry; + + @BeforeEach +- public void setUp() { ++ void setUp() { + metricRegistry = new MetricRegistry(); + } + + @Test +- public void test_WHEN_EmptyConfig_THEN_Fail() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> new CustomLabelMapper(Collections.emptyList())); ++ void _WHEN_EmptyConfig_THEN_Fail() { ++ assertThatThrownBy(() -> new CustomLabelMapper(ImmutableList.of())) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void test_WHEN_NoMatches_THEN_ShouldReturnDefaultSample() { ++ void _WHEN_NoMatches_THEN_ShouldReturnDefaultSample() { + final List mapperConfigs = + Arrays.asList( + new MapperConfig("client-nope.*.*.*"), +@@ -53,7 +54,7 @@ class CustomLabelMapperTest { + } + + @Test +- public void test_WHEN_OneMatch_THEN_ShouldReturnConverted() { ++ void _WHEN_OneMatch_THEN_ShouldReturnConverted() { + final Map labels = new HashMap(); + labels.put("service", "${0}"); + final MapperConfig mapperConfig = +@@ -81,7 +82,7 @@ class CustomLabelMapperTest { + } + + @Test +- public void test_WHEN_MoreMatches_THEN_ShouldReturnFirstOne() { ++ void _WHEN_MoreMatches_THEN_ShouldReturnFirstOne() { + final Map labels = new HashMap<>(); + labels.put("service", "${0}"); + final MapperConfig mapperConfig = +@@ -110,7 +111,7 @@ class CustomLabelMapperTest { + } + + @Test +- public void test_WHEN_MoreMatchesReverseOrder_THEN_ShouldReturnFirstOne() { ++ void _WHEN_MoreMatchesReverseOrder_THEN_ShouldReturnFirstOne() { + final Map labels = new LinkedHashMap<>(); + labels.put("service", "${0}"); + labels.put("status", "${1}"); +@@ -145,7 +146,7 @@ class CustomLabelMapperTest { + } + + @Test +- public void test_WHEN_MoreToFormatInLabelsAndName_THEN_ShouldReturnCorrectSample() { ++ void _WHEN_MoreToFormatInLabelsAndName_THEN_ShouldReturnCorrectSample() { + final Map labels = new LinkedHashMap<>(); + labels.put("service", "${0}_${1}"); + labels.put("status", "s_${1}"); +@@ -176,7 +177,7 @@ class CustomLabelMapperTest { + } + + @Test +- public void test_WHEN_AdditionalLabels_THEN_ShouldReturnCorrectSample() { ++ void _WHEN_AdditionalLabels_THEN_ShouldReturnCorrectSample() { + final Map labels = new LinkedHashMap<>(); + labels.put("service", "${0}"); + labels.put("status", "s_${1}"); +--- a/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/GraphiteNamePatternTest.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/GraphiteNamePatternTest.java +@@ -1,19 +1,18 @@ + package io.prometheus.metrics.instrumentation.dropwizard5.labels; + +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThat; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + + import java.util.Arrays; +-import java.util.Collections; + import java.util.HashMap; + import java.util.List; + import java.util.Map; +-import org.assertj.core.api.Assertions; + import org.junit.jupiter.api.Test; + +-class GraphiteNamePatternTest { ++final class GraphiteNamePatternTest { + + @Test +- public void createNew_WHEN_InvalidPattern_THEN_ShouldThrowException() { ++ void createNew_WHEN_InvalidPattern_THEN_ShouldThrowException() { + List invalidPatterns = + Arrays.asList( + "", +@@ -32,14 +31,14 @@ class GraphiteNamePatternTest { + "org.test.contr.oller.gather.status..400", + "org.test.controller.gather.status..400"); + for (String pattern : invalidPatterns) { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> new GraphiteNamePattern(pattern)) +- .withMessageContaining(pattern); ++ assertThatThrownBy(() -> new GraphiteNamePattern(pattern)) ++ .isInstanceOf(IllegalArgumentException.class) ++ .hasMessageContaining(pattern); + } + } + + @Test +- public void createNew_WHEN_ValidPattern_THEN_ShouldCreateThePatternSuccessfully() { ++ void createNew_WHEN_ValidPattern_THEN_ShouldCreateThePatternSuccessfully() { + final List validPatterns = + Arrays.asList( + "org.test.controller.gather.status.400", +@@ -54,7 +53,7 @@ class GraphiteNamePatternTest { + } + + @Test +- public void createNew_WHEN_ValidPattern_THEN_ShouldInitInternalPatternSuccessfully() { ++ void createNew_WHEN_ValidPattern_THEN_ShouldInitInternalPatternSuccessfully() { + final Map validPatterns = new HashMap(); + validPatterns.put( + "org.test.controller.gather.status.400", "^\\Qorg.test.controller.gather.status.400\\E$"); +@@ -69,25 +68,25 @@ class GraphiteNamePatternTest { + + for (Map.Entry expected : validPatterns.entrySet()) { + final GraphiteNamePattern pattern = new GraphiteNamePattern(expected.getKey()); +- Assertions.assertThat(pattern.getPatternString()).isEqualTo(expected.getValue()); ++ assertThat(pattern.getPatternString()).isEqualTo(expected.getValue()); + } + } + + @Test +- public void match_WHEN_NotMatchingMetricNameProvided_THEN_ShouldNotMatch() { ++ void match_WHEN_NotMatchingMetricNameProvided_THEN_ShouldNotMatch() { + final GraphiteNamePattern pattern = new GraphiteNamePattern("org.test.controller.*.status.*"); + final List notMatchingMetricNamed = + Arrays.asList("org.test.controller.status.400", "", null); + + for (String metricName : notMatchingMetricNamed) { +- Assertions.assertThat(pattern.matches(metricName)) ++ assertThat(pattern.matches(metricName)) + .as("Matching [%s] against [%s]", metricName, pattern.getPatternString()) + .isFalse(); + } + } + + @Test +- public void match_WHEN_MatchingMetricNameProvided_THEN_ShouldMatch() { ++ void match_WHEN_MatchingMetricNameProvided_THEN_ShouldMatch() { + final GraphiteNamePattern pattern = new GraphiteNamePattern("org.test.controller.*.status.*"); + final List matchingMetricNamed = + Arrays.asList( +@@ -98,47 +97,46 @@ class GraphiteNamePatternTest { + "org.test.controller..status.*"); + + for (String metricName : matchingMetricNamed) { +- Assertions.assertThat(pattern.matches(metricName)) ++ assertThat(pattern.matches(metricName)) + .as("Matching [%s] against [%s]", metricName, pattern.getPatternString()) + .isTrue(); + } + } + + @Test +- public void extractParameters() { ++ void extractParameters() { + GraphiteNamePattern pattern; + Map expected = new HashMap(); + expected.put("${0}", "gather"); + expected.put("${1}", "400"); + pattern = new GraphiteNamePattern("org.test.controller.*.status.*"); +- Assertions.assertThat(pattern.extractParameters("org.test.controller.gather.status.400")) +- .isEqualTo(expected); ++ assertThat(pattern.extractParameters("org.test.controller.gather.status.400")) ++ .containsExactlyInAnyOrderEntriesOf(expected); + + expected = new HashMap(); + expected.put("${0}", "org"); + expected.put("${1}", "gather"); + expected.put("${2}", "400"); + pattern = new GraphiteNamePattern("*.test.controller.*.status.*"); +- Assertions.assertThat(pattern.extractParameters("org.test.controller.gather.status.400")) +- .isEqualTo(expected); ++ assertThat(pattern.extractParameters("org.test.controller.gather.status.400")) ++ .containsExactlyInAnyOrderEntriesOf(expected); + } + + @Test +- public void extractParameters_WHEN_emptyStringInDottedMetricsName_THEN_ShouldReturnEmptyString() { ++ void extractParameters_WHEN_emptyStringInDottedMetricsName_THEN_ShouldReturnEmptyString() { + GraphiteNamePattern pattern; + Map expected = new HashMap(); + expected.put("${0}", ""); + expected.put("${1}", "400"); + pattern = new GraphiteNamePattern("org.test.controller.*.status.*"); +- Assertions.assertThat(pattern.extractParameters("org.test.controller..status.400")) +- .isEqualTo(expected); ++ assertThat(pattern.extractParameters("org.test.controller..status.400")) ++ .containsExactlyInAnyOrderEntriesOf(expected); + } + + @Test +- public void extractParameters_WHEN_moreDots_THEN_ShouldReturnNoMatches() { ++ void extractParameters_WHEN_moreDots_THEN_ShouldReturnNoMatches() { + GraphiteNamePattern pattern; + pattern = new GraphiteNamePattern("org.test.controller.*.status.*"); +- Assertions.assertThat(pattern.extractParameters("org.test.controller...status.400")) +- .isEqualTo(Collections.emptyMap()); ++ assertThat(pattern.extractParameters("org.test.controller...status.400")).isEmpty(); + } + } +--- a/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/MapperConfigTest.java ++++ b/prometheus-metrics-instrumentation-dropwizard5/src/test/java/io/prometheus/metrics/instrumentation/dropwizard5/labels/MapperConfigTest.java +@@ -1,58 +1,58 @@ + package io.prometheus.metrics.instrumentation.dropwizard5.labels; + + import static org.assertj.core.api.Assertions.assertThat; +-import static org.assertj.core.api.Assertions.assertThatExceptionOfType; ++import static org.assertj.core.api.Assertions.assertThatThrownBy; + +-import java.util.Collections; ++import com.google.common.collect.ImmutableMap; + import java.util.HashMap; + import java.util.Map; + import org.junit.jupiter.api.Test; + +-class MapperConfigTest { ++final class MapperConfigTest { + @Test +- public void setMatch_WHEN_ExpressionMatchesPattern_AllGood() { ++ void setMatch_WHEN_ExpressionMatchesPattern_AllGood() { + final MapperConfig mapperConfig = new MapperConfig(); + mapperConfig.setMatch("com.company.meter.*"); + assertThat(mapperConfig.getMatch()).isEqualTo("com.company.meter.*"); + } + + @Test +- public void setMatch_WHEN_ExpressionDoesnNotMatchPattern_ThrowException() { +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> new MapperConfig().setMatch("com.company.meter.**.yay")); ++ void setMatch_WHEN_ExpressionDoesnNotMatchPattern_ThrowException() { ++ assertThatThrownBy(() -> new MapperConfig().setMatch("com.company.meter.**.yay")) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void setLabels_WHEN_ExpressionMatchesPattern_AllGood() { ++ void setLabels_WHEN_ExpressionMatchesPattern_AllGood() { + final MapperConfig mapperConfig = new MapperConfig(); + final Map labels = new HashMap<>(); + labels.put("valid", "${0}"); + mapperConfig.setLabels(labels); +- assertThat(mapperConfig.getLabels()).isEqualTo(labels); ++ assertThat(mapperConfig.getLabels()).containsExactlyInAnyOrderEntriesOf(labels); + } + + @Test +- public void setLabels_WHEN_ExpressionDoesnNotMatchPattern_ThrowException() { ++ void setLabels_WHEN_ExpressionDoesnNotMatchPattern_ThrowException() { + final MapperConfig mapperConfig = new MapperConfig(); + final Map labels = new HashMap<>(); + labels.put("valid", "${0}"); + labels.put("not valid", "${0}"); +- assertThatExceptionOfType(IllegalArgumentException.class) +- .isThrownBy(() -> mapperConfig.setLabels(labels)); ++ assertThatThrownBy(() -> mapperConfig.setLabels(labels)) ++ .isInstanceOf(IllegalArgumentException.class); + } + + @Test +- public void toString_WHEN_EmptyConfig_AllGood() { ++ void toString_WHEN_EmptyConfig_AllGood() { + final MapperConfig mapperConfig = new MapperConfig(); + assertThat(mapperConfig).hasToString("MapperConfig{match=null, name=null, labels={}}"); + } + + @Test +- public void toString_WHEN_FullyConfigured_AllGood() { ++ void toString_WHEN_FullyConfigured_AllGood() { + final MapperConfig mapperConfig = new MapperConfig(); + mapperConfig.setMatch("com.company.meter.*.foo"); + mapperConfig.setName("foo"); +- mapperConfig.setLabels(Collections.singletonMap("type", "${0}")); ++ mapperConfig.setLabels(ImmutableMap.of("type", "${0}")); + assertThat(mapperConfig) + .hasToString("MapperConfig{match=com.company.meter.*.foo, name=foo, labels={type=${0}}}"); + } +--- a/prometheus-metrics-instrumentation-guava/src/main/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollector.java ++++ b/prometheus-metrics-instrumentation-guava/src/main/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollector.java +@@ -1,8 +1,11 @@ + package io.prometheus.metrics.instrumentation.guava; + ++import static java.util.Collections.unmodifiableList; ++ + import com.google.common.cache.Cache; + import com.google.common.cache.CacheStats; + import com.google.common.cache.LoadingCache; ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.model.registry.MultiCollector; + import io.prometheus.metrics.model.snapshots.CounterSnapshot; + import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +@@ -10,7 +13,6 @@ import io.prometheus.metrics.model.snapshots.Labels; + import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import io.prometheus.metrics.model.snapshots.SummarySnapshot; + import java.util.Arrays; +-import java.util.Collections; + import java.util.List; + import java.util.Map; + import java.util.concurrent.ConcurrentHashMap; +@@ -66,7 +68,7 @@ public class CacheMetricsCollector implements MultiCollector { + "guava_cache_load_duration_seconds"; + + private static final List ALL_METRIC_NAMES = +- Collections.unmodifiableList( ++ unmodifiableList( + Arrays.asList( + METRIC_NAME_CACHE_HIT, + METRIC_NAME_CACHE_MISS, +@@ -114,7 +116,7 @@ public class CacheMetricsCollector implements MultiCollector { + @Override + public MetricSnapshots collect() { + final MetricSnapshots.Builder metricSnapshotsBuilder = MetricSnapshots.builder(); +- final List labelNames = Collections.singletonList("cache"); ++ final List labelNames = ImmutableList.of("cache"); + + final CounterSnapshot.Builder cacheHitTotal = + CounterSnapshot.builder().name(METRIC_NAME_CACHE_HIT).help("Cache hit totals"); +@@ -147,7 +149,7 @@ public class CacheMetricsCollector implements MultiCollector { + .help("Cache load duration: both success and failures"); + + for (final Map.Entry> c : children.entrySet()) { +- final List cacheName = Collections.singletonList(c.getKey()); ++ final List cacheName = ImmutableList.of(c.getKey()); + final Labels labels = Labels.of(labelNames, cacheName); + + final CacheStats stats = c.getValue().stats(); +--- a/prometheus-metrics-instrumentation-guava/src/test/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollectorTest.java ++++ b/prometheus-metrics-instrumentation-guava/src/test/java/io/prometheus/metrics/instrumentation/guava/CacheMetricsCollectorTest.java +@@ -23,10 +23,10 @@ import java.nio.charset.StandardCharsets; + import java.util.List; + import org.junit.jupiter.api.Test; + +-class CacheMetricsCollectorTest { ++final class CacheMetricsCollectorTest { + + @Test +- public void cacheExposesMetricsForHitMissAndEviction() { ++ void cacheExposesMetricsForHitMissAndEviction() { + final Cache cache = + CacheBuilder.newBuilder().maximumSize(2).recordStats().build(); + +@@ -74,8 +74,8 @@ class CacheMetricsCollectorTest { + + @SuppressWarnings("unchecked") + @Test +- public void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception { +- final CacheLoader loader = mock(CacheLoader.class); ++ void loadingCacheExposesMetricsForLoadsAndExceptions() throws Exception { ++ final CacheLoader loader = mock(); + when(loader.load(anyString())) + .thenReturn("First User") + .thenThrow(new RuntimeException("Seconds time fails")) +@@ -109,11 +109,11 @@ class CacheMetricsCollectorTest { + getDataPointSnapshot(registry, "guava_cache_load_duration_seconds", "loadingusers"); + + assertThat(loadDuration.getCount()).isEqualTo(3); +- assertThat(loadDuration.getSum()).isGreaterThan(0); ++ assertThat(loadDuration.getSum()).isPositive(); + } + + @Test +- public void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() { ++ void getPrometheusNamesHasSameSizeAsMetricSizeWhenScraping() { + final CacheMetricsCollector collector = new CacheMetricsCollector(); + + final PrometheusRegistry registry = new PrometheusRegistry(); +@@ -126,7 +126,7 @@ class CacheMetricsCollectorTest { + } + + @Test +- public void collectedMetricNamesAreKnownPrometheusNames() { ++ void collectedMetricNamesAreKnownPrometheusNames() { + final CacheMetricsCollector collector = new CacheMetricsCollector(); + + final PrometheusRegistry registry = new PrometheusRegistry(); +--- a/prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/JvmNativeMemoryMetrics.java ++++ b/prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/JvmNativeMemoryMetrics.java +@@ -89,7 +89,7 @@ public class JvmNativeMemoryMetrics { + private static final String JVM_NATIVE_MEMORY_COMMITTED_BYTES = + "jvm_native_memory_committed_bytes"; + +- private static final Pattern pattern = ++ private static final Pattern PATTERN = + Pattern.compile("\\s*([A-Z][A-Za-z\\s]*[A-Za-z]+).*reserved=(\\d+), committed=(\\d+)"); + + /** Package private. For testing only. */ +@@ -133,7 +133,7 @@ public class JvmNativeMemoryMetrics { + return callback -> { + String summary = vmNativeMemorySummaryInBytesOrEmpty(); + if (!summary.isEmpty()) { +- Matcher matcher = pattern.matcher(summary); ++ Matcher matcher = PATTERN.matcher(summary); + while (matcher.find()) { + String category = matcher.group(1); + long value = +--- a/prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/JvmThreadsMetrics.java ++++ b/prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/JvmThreadsMetrics.java +@@ -176,7 +176,7 @@ public class JvmThreadsMetrics { + } + + private double nullSafeArrayLength(long[] array) { +- return null == array ? 0 : array.length; ++ return array == null ? 0 : array.length; + } + + public static Builder builder() { +--- a/prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/ProcessMetrics.java ++++ b/prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/ProcessMetrics.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.instrumentation.jvm; + ++import static java.nio.charset.StandardCharsets.UTF_8; ++ + import io.prometheus.metrics.config.PrometheusProperties; + import io.prometheus.metrics.core.metrics.CounterWithCallback; + import io.prometheus.metrics.core.metrics.GaugeWithCallback; +@@ -14,7 +16,6 @@ import java.lang.management.OperatingSystemMXBean; + import java.lang.management.RuntimeMXBean; + import java.lang.reflect.InvocationTargetException; + import java.lang.reflect.Method; +-import java.nio.charset.StandardCharsets; + import java.nio.file.Files; + + /** +@@ -243,8 +244,7 @@ public class ProcessMetrics { + @Override + public String lineStartingWith(File file, String prefix) throws IOException { + try (BufferedReader reader = +- new BufferedReader( +- new InputStreamReader(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8))) { ++ new BufferedReader(new InputStreamReader(Files.newInputStream(file.toPath()), UTF_8))) { + String line = reader.readLine(); + while (line != null) { + if (line.startsWith(prefix)) { +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmBufferPoolMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmBufferPoolMetricsTest.java +@@ -2,7 +2,8 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + +@@ -14,15 +15,14 @@ import java.lang.management.BufferPoolMXBean; + import java.util.Arrays; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmBufferPoolMetricsTest { ++final class JvmBufferPoolMetricsTest { + +- private final BufferPoolMXBean directBuffer = Mockito.mock(BufferPoolMXBean.class); +- private final BufferPoolMXBean mappedBuffer = Mockito.mock(BufferPoolMXBean.class); ++ private final BufferPoolMXBean directBuffer = mock(); ++ private final BufferPoolMXBean mappedBuffer = mock(); + + @BeforeEach +- public void setUp() { ++ void setUp() { + when(directBuffer.getName()).thenReturn("direct"); + when(directBuffer.getCount()).thenReturn(2L); + when(directBuffer.getMemoryUsed()).thenReturn(1234L); +@@ -34,7 +34,7 @@ class JvmBufferPoolMetricsTest { + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmBufferPoolMetrics.builder() + .bufferPoolBeans(Arrays.asList(mappedBuffer, directBuffer)) +@@ -62,7 +62,7 @@ class JvmBufferPoolMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder().nameMustNotBeEqualTo("jvm_buffer_pool_used_bytes").build(); + +@@ -72,9 +72,9 @@ class JvmBufferPoolMetricsTest { + .register(registry); + registry.scrape(filter); + +- verify(directBuffer, times(0)).getMemoryUsed(); +- verify(mappedBuffer, times(0)).getMemoryUsed(); +- verify(directBuffer, times(1)).getTotalCapacity(); +- verify(mappedBuffer, times(1)).getTotalCapacity(); ++ verify(directBuffer, never()).getMemoryUsed(); ++ verify(mappedBuffer, never()).getMemoryUsed(); ++ verify(directBuffer).getTotalCapacity(); ++ verify(mappedBuffer).getTotalCapacity(); + } + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmClassLoadingMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmClassLoadingMetricsTest.java +@@ -2,7 +2,8 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + +@@ -13,21 +14,20 @@ import java.io.IOException; + import java.lang.management.ClassLoadingMXBean; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmClassLoadingMetricsTest { ++final class JvmClassLoadingMetricsTest { + +- private final ClassLoadingMXBean mockClassLoadingBean = Mockito.mock(ClassLoadingMXBean.class); ++ private final ClassLoadingMXBean mockClassLoadingBean = mock(); + + @BeforeEach +- public void setUp() { ++ void setUp() { + when(mockClassLoadingBean.getLoadedClassCount()).thenReturn(1000); + when(mockClassLoadingBean.getTotalLoadedClassCount()).thenReturn(2000L); + when(mockClassLoadingBean.getUnloadedClassCount()).thenReturn(500L); + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmClassLoadingMetrics.builder().classLoadingBean(mockClassLoadingBean).register(registry); + MetricSnapshots snapshots = registry.scrape(); +@@ -48,7 +48,7 @@ class JvmClassLoadingMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder().nameMustNotBeEqualTo("jvm_classes_currently_loaded").build(); + +@@ -56,7 +56,7 @@ class JvmClassLoadingMetricsTest { + JvmClassLoadingMetrics.builder().classLoadingBean(mockClassLoadingBean).register(registry); + registry.scrape(filter); + +- verify(mockClassLoadingBean, times(0)).getLoadedClassCount(); +- verify(mockClassLoadingBean, times(1)).getTotalLoadedClassCount(); ++ verify(mockClassLoadingBean, never()).getLoadedClassCount(); ++ verify(mockClassLoadingBean).getTotalLoadedClassCount(); + } + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmCompilationMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmCompilationMetricsTest.java +@@ -2,6 +2,7 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; ++import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + import static org.mockito.internal.verification.VerificationModeFactory.times; +@@ -13,20 +14,19 @@ import java.io.IOException; + import java.lang.management.CompilationMXBean; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmCompilationMetricsTest { ++final class JvmCompilationMetricsTest { + +- private final CompilationMXBean mockCompilationBean = Mockito.mock(CompilationMXBean.class); ++ private final CompilationMXBean mockCompilationBean = mock(); + + @BeforeEach +- public void setUp() { ++ void setUp() { + when(mockCompilationBean.getTotalCompilationTime()).thenReturn(10000L); + when(mockCompilationBean.isCompilationTimeMonitoringSupported()).thenReturn(true); + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmCompilationMetrics.builder().compilationBean(mockCompilationBean).register(registry); + MetricSnapshots snapshots = registry.scrape(); +@@ -42,7 +42,7 @@ class JvmCompilationMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder() + .nameMustNotBeEqualTo("jvm_compilation_time_seconds_total") +@@ -53,6 +53,6 @@ class JvmCompilationMetricsTest { + MetricSnapshots snapshots = registry.scrape(filter); + + verify(mockCompilationBean, times(0)).getTotalCompilationTime(); +- assertThat(snapshots.size()).isZero(); ++ assertThat(snapshots.size()).isEqualTo(0); + } + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmGarbageCollectorMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmGarbageCollectorMetricsTest.java +@@ -2,7 +2,8 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + +@@ -15,15 +16,14 @@ import java.util.Arrays; + import java.util.concurrent.TimeUnit; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmGarbageCollectorMetricsTest { ++final class JvmGarbageCollectorMetricsTest { + +- private final GarbageCollectorMXBean mockGcBean1 = Mockito.mock(GarbageCollectorMXBean.class); +- private final GarbageCollectorMXBean mockGcBean2 = Mockito.mock(GarbageCollectorMXBean.class); ++ private final GarbageCollectorMXBean mockGcBean1 = mock(); ++ private final GarbageCollectorMXBean mockGcBean2 = mock(); + + @BeforeEach +- public void setUp() { ++ void setUp() { + when(mockGcBean1.getName()).thenReturn("MyGC1"); + when(mockGcBean1.getCollectionCount()).thenReturn(100L); + when(mockGcBean1.getCollectionTime()).thenReturn(TimeUnit.SECONDS.toMillis(10)); +@@ -33,7 +33,7 @@ class JvmGarbageCollectorMetricsTest { + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmGarbageCollectorMetrics.builder() + .garbageCollectorBeans(Arrays.asList(mockGcBean1, mockGcBean2)) +@@ -54,7 +54,7 @@ class JvmGarbageCollectorMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder().nameMustNotBeEqualTo("jvm_gc_collection_seconds").build(); + +@@ -64,8 +64,8 @@ class JvmGarbageCollectorMetricsTest { + .register(registry); + MetricSnapshots snapshots = registry.scrape(filter); + +- verify(mockGcBean1, times(0)).getCollectionTime(); +- verify(mockGcBean1, times(0)).getCollectionCount(); +- assertThat(snapshots.size()).isZero(); ++ verify(mockGcBean1, never()).getCollectionTime(); ++ verify(mockGcBean1, never()).getCollectionCount(); ++ assertThat(snapshots.size()).isEqualTo(0); + } + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmMemoryMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmMemoryMetricsTest.java +@@ -2,7 +2,8 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + +@@ -16,22 +17,21 @@ import java.lang.management.MemoryUsage; + import java.util.Arrays; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmMemoryMetricsTest { ++final class JvmMemoryMetricsTest { + +- private final MemoryMXBean mockMemoryBean = Mockito.mock(MemoryMXBean.class); +- private final MemoryPoolMXBean mockPoolsBeanEdenSpace = Mockito.mock(MemoryPoolMXBean.class); +- private final MemoryPoolMXBean mockPoolsBeanOldGen = Mockito.mock(MemoryPoolMXBean.class); +- private final MemoryUsage memoryUsageHeap = Mockito.mock(MemoryUsage.class); +- private final MemoryUsage memoryUsageNonHeap = Mockito.mock(MemoryUsage.class); +- private final MemoryUsage memoryUsagePoolEdenSpace = Mockito.mock(MemoryUsage.class); +- private final MemoryUsage memoryUsagePoolOldGen = Mockito.mock(MemoryUsage.class); +- private final MemoryUsage memoryUsagePoolCollectionEdenSpace = Mockito.mock(MemoryUsage.class); +- private final MemoryUsage memoryUsagePoolCollectionOldGen = Mockito.mock(MemoryUsage.class); ++ private final MemoryMXBean mockMemoryBean = mock(); ++ private final MemoryPoolMXBean mockPoolsBeanEdenSpace = mock(); ++ private final MemoryPoolMXBean mockPoolsBeanOldGen = mock(); ++ private final MemoryUsage memoryUsageHeap = mock(); ++ private final MemoryUsage memoryUsageNonHeap = mock(); ++ private final MemoryUsage memoryUsagePoolEdenSpace = mock(); ++ private final MemoryUsage memoryUsagePoolOldGen = mock(); ++ private final MemoryUsage memoryUsagePoolCollectionEdenSpace = mock(); ++ private final MemoryUsage memoryUsagePoolCollectionOldGen = mock(); + + @BeforeEach +- public void setUp() { ++ void setUp() { + when(mockMemoryBean.getHeapMemoryUsage()).thenReturn(memoryUsageHeap); + when(mockMemoryBean.getNonHeapMemoryUsage()).thenReturn(memoryUsageNonHeap); + +@@ -79,7 +79,7 @@ class JvmMemoryMetricsTest { + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmMemoryMetrics.builder() + .withMemoryBean(mockMemoryBean) +@@ -157,7 +157,7 @@ class JvmMemoryMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder().nameMustNotBeEqualTo("jvm_memory_pool_used_bytes").build(); + +@@ -168,9 +168,9 @@ class JvmMemoryMetricsTest { + .register(registry); + registry.scrape(filter); + +- verify(memoryUsagePoolEdenSpace, times(0)).getUsed(); +- verify(memoryUsagePoolOldGen, times(0)).getUsed(); +- verify(memoryUsagePoolEdenSpace, times(1)).getMax(); +- verify(memoryUsagePoolOldGen, times(1)).getMax(); ++ verify(memoryUsagePoolEdenSpace, never()).getUsed(); ++ verify(memoryUsagePoolOldGen, never()).getUsed(); ++ verify(memoryUsagePoolEdenSpace).getMax(); ++ verify(memoryUsagePoolOldGen).getMax(); + } + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmMemoryPoolAllocationMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmMemoryPoolAllocationMetricsTest.java +@@ -11,10 +11,10 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshot; + import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import org.junit.jupiter.api.Test; + +-class JvmMemoryPoolAllocationMetricsTest { ++final class JvmMemoryPoolAllocationMetricsTest { + + @Test +- public void testListenerLogic() { ++ void listenerLogic() { + PrometheusRegistry registry = new PrometheusRegistry(); + Counter counter = Counter.builder().name("test").labelNames("pool").register(registry); + AllocationCountingNotificationListener listener = +@@ -60,7 +60,7 @@ class JvmMemoryPoolAllocationMetricsTest { + } + } + } +- fail("pool " + poolName + " not found."); ++ fail("pool %s not found.", poolName); + return 0.0; + } + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmMetricsTest.java +@@ -8,7 +8,7 @@ import java.lang.management.ManagementFactory; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + +-class JvmMetricsTest { ++final class JvmMetricsTest { + + @BeforeEach + void setUp() { +@@ -16,11 +16,11 @@ class JvmMetricsTest { + } + + @Test +- public void testRegisterIdempotent() { ++ void registerIdempotent() { + PrometheusRegistry registry = new PrometheusRegistry(); +- assertThat(registry.scrape().size()).isZero(); ++ assertThat(registry.scrape().size()).isEqualTo(0); + JvmMetrics.builder().register(registry); +- assertThat(registry.scrape().size()).isGreaterThan(0); ++ assertThat(registry.scrape().size()).isPositive(); + JvmMetrics.builder().register(registry); + } + +@@ -33,7 +33,7 @@ class JvmMetricsTest { + } + + @Test +- void testJvmMetrics() { ++ void jvmMetrics() { + JvmMetrics.builder(PrometheusProperties.get()).register(); + JvmMetrics.builder().register(); + } +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmNativeMemoryMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmNativeMemoryMetricsTest.java +@@ -2,6 +2,7 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; ++import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; + + import io.prometheus.metrics.config.PrometheusProperties; +@@ -9,16 +10,14 @@ import io.prometheus.metrics.model.registry.PrometheusRegistry; + import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import java.io.IOException; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmNativeMemoryMetricsTest { ++final class JvmNativeMemoryMetricsTest { + + @Test +- public void testNativeMemoryTrackingFail() throws IOException { ++ void nativeMemoryTrackingFail() throws IOException { + JvmNativeMemoryMetrics.isEnabled.set(true); + +- JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = +- Mockito.mock(JvmNativeMemoryMetrics.PlatformMBeanServerAdapter.class); ++ JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = mock(); + when(adapter.vmNativeMemorySummaryInBytes()).thenThrow(new RuntimeException("mock")); + + PrometheusRegistry registry = new PrometheusRegistry(); +@@ -39,11 +38,10 @@ class JvmNativeMemoryMetricsTest { + } + + @Test +- public void testNativeMemoryTrackingEmpty() throws IOException { ++ void nativeMemoryTrackingEmpty() throws IOException { + JvmNativeMemoryMetrics.isEnabled.set(true); + +- JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = +- Mockito.mock(JvmNativeMemoryMetrics.PlatformMBeanServerAdapter.class); ++ JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = mock(); + when(adapter.vmNativeMemorySummaryInBytes()).thenReturn(""); + + PrometheusRegistry registry = new PrometheusRegistry(); +@@ -56,11 +54,10 @@ class JvmNativeMemoryMetricsTest { + } + + @Test +- public void testNativeMemoryTrackingDisabled() throws IOException { ++ void nativeMemoryTrackingDisabled() throws IOException { + JvmNativeMemoryMetrics.isEnabled.set(true); + +- JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = +- Mockito.mock(JvmNativeMemoryMetrics.PlatformMBeanServerAdapter.class); ++ JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = mock(); + when(adapter.vmNativeMemorySummaryInBytes()) + .thenReturn("Native memory tracking is not enabled"); + +@@ -74,11 +71,10 @@ class JvmNativeMemoryMetricsTest { + } + + @Test +- public void testNativeMemoryTrackingEnabled() throws IOException { ++ void nativeMemoryTrackingEnabled() throws IOException { + JvmNativeMemoryMetrics.isEnabled.set(true); + +- JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = +- Mockito.mock(JvmNativeMemoryMetrics.PlatformMBeanServerAdapter.class); ++ JvmNativeMemoryMetrics.PlatformMBeanServerAdapter adapter = mock(); + when(adapter.vmNativeMemorySummaryInBytes()) + .thenReturn( + "Native Memory Tracking:\n" +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmRuntimeInfoMetricTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmRuntimeInfoMetricTest.java +@@ -8,10 +8,10 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshots; + import java.io.IOException; + import org.junit.jupiter.api.Test; + +-class JvmRuntimeInfoMetricTest { ++final class JvmRuntimeInfoMetricTest { + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmRuntimeInfoMetric.builder() + .version("1.8.0_382-b05") +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmThreadsMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmThreadsMetricsTest.java +@@ -2,7 +2,8 @@ package io.prometheus.metrics.instrumentation.jvm; + + import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMetricsFormat; + import static org.assertj.core.api.Assertions.assertThat; +-import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + +@@ -19,17 +20,16 @@ import java.util.Map; + import java.util.concurrent.CountDownLatch; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class JvmThreadsMetricsTest { ++final class JvmThreadsMetricsTest { + +- private final ThreadMXBean mockThreadsBean = Mockito.mock(ThreadMXBean.class); +- private final ThreadInfo mockThreadInfoBlocked = Mockito.mock(ThreadInfo.class); +- private final ThreadInfo mockThreadInfoRunnable1 = Mockito.mock(ThreadInfo.class); +- private final ThreadInfo mockThreadInfoRunnable2 = Mockito.mock(ThreadInfo.class); ++ private final ThreadMXBean mockThreadsBean = mock(); ++ private final ThreadInfo mockThreadInfoBlocked = mock(); ++ private final ThreadInfo mockThreadInfoRunnable1 = mock(); ++ private final ThreadInfo mockThreadInfoRunnable2 = mock(); + + @BeforeEach +- public void setUp() { ++ void setUp() { + when(mockThreadsBean.getThreadCount()).thenReturn(300); + when(mockThreadsBean.getDaemonThreadCount()).thenReturn(200); + when(mockThreadsBean.getPeakThreadCount()).thenReturn(301); +@@ -48,7 +48,7 @@ class JvmThreadsMetricsTest { + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + JvmThreadsMetrics.builder().threadBean(mockThreadsBean).isNativeImage(false).register(registry); + MetricSnapshots snapshots = registry.scrape(); +@@ -87,7 +87,7 @@ class JvmThreadsMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder().nameMustNotBeEqualTo("jvm_threads_deadlocked").build(); + +@@ -95,12 +95,12 @@ class JvmThreadsMetricsTest { + JvmThreadsMetrics.builder().threadBean(mockThreadsBean).isNativeImage(false).register(registry); + registry.scrape(filter); + +- verify(mockThreadsBean, times(0)).findDeadlockedThreads(); +- verify(mockThreadsBean, times(1)).getThreadCount(); ++ verify(mockThreadsBean, never()).findDeadlockedThreads(); ++ verify(mockThreadsBean).getThreadCount(); + } + + @Test +- public void testInvalidThreadIds() { ++ void invalidThreadIds() { + try { + String javaVersion = System.getProperty("java.version"); // Example: "21.0.2" + String majorJavaVersion = javaVersion.replaceAll("\\..*", ""); // Example: "21" +--- a/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/ProcessMetricsTest.java ++++ b/prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/ProcessMetricsTest.java +@@ -4,7 +4,8 @@ import static io.prometheus.metrics.instrumentation.jvm.TestUtil.convertToOpenMe + import static org.assertj.core.api.Assertions.assertThat; + import static org.mockito.ArgumentMatchers.any; + import static org.mockito.ArgumentMatchers.eq; +-import static org.mockito.Mockito.times; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.never; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + +@@ -17,20 +18,17 @@ import java.lang.management.RuntimeMXBean; + import java.util.concurrent.TimeUnit; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; +-import org.mockito.Mockito; + +-class ProcessMetricsTest { ++final class ProcessMetricsTest { + +- private final com.sun.management.UnixOperatingSystemMXBean sunOsBean = +- Mockito.mock(com.sun.management.UnixOperatingSystemMXBean.class); +- private final java.lang.management.OperatingSystemMXBean javaOsBean = +- Mockito.mock(java.lang.management.OperatingSystemMXBean.class); +- private final ProcessMetrics.Grepper linuxGrepper = Mockito.mock(ProcessMetrics.Grepper.class); +- private final ProcessMetrics.Grepper windowsGrepper = Mockito.mock(ProcessMetrics.Grepper.class); +- private final RuntimeMXBean runtimeBean = Mockito.mock(RuntimeMXBean.class); ++ private final com.sun.management.UnixOperatingSystemMXBean sunOsBean = mock(); ++ private final java.lang.management.OperatingSystemMXBean javaOsBean = mock(); ++ private final ProcessMetrics.Grepper linuxGrepper = mock(); ++ private final ProcessMetrics.Grepper windowsGrepper = mock(); ++ private final RuntimeMXBean runtimeBean = mock(); + + @BeforeEach +- public void setUp() throws IOException { ++ void setUp() throws IOException { + when(sunOsBean.getProcessCpuTime()).thenReturn(TimeUnit.MILLISECONDS.toNanos(72)); + when(sunOsBean.getOpenFileDescriptorCount()).thenReturn(127L); + when(sunOsBean.getMaxFileDescriptorCount()).thenReturn(244L); +@@ -42,7 +40,7 @@ class ProcessMetricsTest { + } + + @Test +- public void testGoodCase() throws IOException { ++ void goodCase() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + ProcessMetrics.builder() + .osBean(sunOsBean) +@@ -89,7 +87,7 @@ class ProcessMetricsTest { + } + + @Test +- public void testMinimal() throws IOException { ++ void minimal() throws IOException { + PrometheusRegistry registry = new PrometheusRegistry(); + ProcessMetrics.builder() + .osBean(javaOsBean) +@@ -109,7 +107,7 @@ class ProcessMetricsTest { + } + + @Test +- public void testIgnoredMetricNotScraped() { ++ void ignoredMetricNotScraped() { + MetricNameFilter filter = + MetricNameFilter.builder().nameMustNotBeEqualTo("process_max_fds").build(); + +@@ -121,7 +119,7 @@ class ProcessMetricsTest { + .register(registry); + registry.scrape(filter); + +- verify(sunOsBean, times(0)).getMaxFileDescriptorCount(); +- verify(sunOsBean, times(1)).getOpenFileDescriptorCount(); ++ verify(sunOsBean, never()).getMaxFileDescriptorCount(); ++ verify(sunOsBean).getOpenFileDescriptorCount(); + } + } +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/MultiCollector.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/MultiCollector.java +@@ -1,8 +1,8 @@ + package io.prometheus.metrics.model.registry; + ++import com.google.common.collect.ImmutableList; + import io.prometheus.metrics.model.snapshots.MetricSnapshot; + import io.prometheus.metrics.model.snapshots.MetricSnapshots; +-import java.util.Collections; + import java.util.List; + import java.util.function.Predicate; + +@@ -67,6 +67,6 @@ public interface MultiCollector { + * runtime it is a good idea to overwrite this and return the names. + */ + default List getPrometheusNames() { +- return Collections.emptyList(); ++ return ImmutableList.of(); + } + } +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java +@@ -1,5 +1,6 @@ + package io.prometheus.metrics.model.registry; + ++import static com.google.common.base.Preconditions.checkState; + import static io.prometheus.metrics.model.snapshots.PrometheusNaming.prometheusName; + + import io.prometheus.metrics.model.snapshots.MetricSnapshot; +@@ -21,22 +22,20 @@ public class PrometheusRegistry { + public void register(Collector collector) { + String prometheusName = collector.getPrometheusName(); + if (prometheusName != null) { +- if (!prometheusNames.add(prometheusName)) { +- throw new IllegalStateException( +- "Can't register " +- + prometheusName +- + " because a metric with that name is already registered."); +- } ++ checkState( ++ prometheusNames.add(prometheusName), ++ "Can't register %s because a metric with that name is already registered.", ++ prometheusName); + } + collectors.add(collector); + } + + public void register(MultiCollector collector) { + for (String prometheusName : collector.getPrometheusNames()) { +- if (!prometheusNames.add(prometheusName)) { +- throw new IllegalStateException( +- "Can't register " + prometheusName + " because that name is already registered."); +- } ++ checkState( ++ prometheusNames.add(prometheusName), ++ "Can't register %s because that name is already registered.", ++ prometheusName); + } + multiCollectors.add(collector); + } +@@ -72,10 +71,10 @@ public class PrometheusRegistry { + MetricSnapshot snapshot = + scrapeRequest == null ? collector.collect() : collector.collect(scrapeRequest); + if (snapshot != null) { +- if (result.containsMetricName(snapshot.getMetadata().getName())) { +- throw new IllegalStateException( +- snapshot.getMetadata().getPrometheusName() + ": duplicate metric name."); +- } ++ checkState( ++ !result.containsMetricName(snapshot.getMetadata().getName()), ++ "%s: duplicate metric name.", ++ snapshot.getMetadata().getPrometheusName()); + result.metricSnapshot(snapshot); + } + } +@@ -83,10 +82,10 @@ public class PrometheusRegistry { + MetricSnapshots snapshots = + scrapeRequest == null ? collector.collect() : collector.collect(scrapeRequest); + for (MetricSnapshot snapshot : snapshots) { +- if (result.containsMetricName(snapshot.getMetadata().getName())) { +- throw new IllegalStateException( +- snapshot.getMetadata().getPrometheusName() + ": duplicate metric name."); +- } ++ checkState( ++ !result.containsMetricName(snapshot.getMetadata().getName()), ++ "%s: duplicate metric name.", ++ snapshot.getMetadata().getPrometheusName()); + result.metricSnapshot(snapshot); + } + } +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/ClassicHistogramBucket.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/ClassicHistogramBucket.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + /** + * Helper class for iterating over {@link ClassicHistogramBuckets}. Note that the {@code count} is + * not cumulative. +@@ -12,16 +14,13 @@ public class ClassicHistogramBucket implements Comparable= 0, ++ "%s: %s cannot have a negative count", ++ count, ++ ClassicHistogramBuckets.class.getSimpleName()); + } + + public long getCount() { +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/ClassicHistogramBuckets.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/ClassicHistogramBuckets.java +@@ -1,8 +1,10 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++import static java.util.Collections.unmodifiableList; ++ + import java.util.ArrayList; + import java.util.Arrays; +-import java.util.Collections; + import java.util.Iterator; + import java.util.List; + import java.util.stream.Stream; +@@ -98,14 +100,11 @@ public class ClassicHistogramBuckets implements Iterable + } + + private static void sortAndValidate(double[] upperBounds, long[] counts) { +- if (upperBounds.length != counts.length) { +- throw new IllegalArgumentException( +- "upperBounds.length == " +- + upperBounds.length +- + " but counts.length == " +- + counts.length +- + ". Expected the same length."); +- } ++ checkArgument( ++ upperBounds.length == counts.length, ++ "upperBounds.length == %s but counts.length == %s. Expected the same length.", ++ upperBounds.length, ++ counts.length); + sort(upperBounds, counts); + validate(upperBounds, counts); + } +@@ -135,28 +134,26 @@ public class ClassicHistogramBuckets implements Iterable + // Preconditions: + // * upperBounds sorted + // * upperBounds and counts have the same length +- if (upperBounds.length == 0) { +- throw new IllegalArgumentException( +- ClassicHistogramBuckets.class.getSimpleName() +- + " cannot be empty. They must contain at least the +Inf bucket."); +- } +- if (upperBounds[upperBounds.length - 1] != Double.POSITIVE_INFINITY) { +- throw new IllegalArgumentException( +- ClassicHistogramBuckets.class.getSimpleName() + " must contain the +Inf bucket."); +- } ++ checkArgument( ++ upperBounds.length != 0, ++ "%s cannot be empty. They must contain at least the +Inf bucket.", ++ ClassicHistogramBuckets.class.getSimpleName()); ++ checkArgument( ++ upperBounds[upperBounds.length - 1] == Double.POSITIVE_INFINITY, ++ "%s must contain the +Inf bucket.", ++ ClassicHistogramBuckets.class.getSimpleName()); + for (int i = 0; i < upperBounds.length; i++) { +- if (Double.isNaN(upperBounds[i])) { +- throw new IllegalArgumentException( +- "Cannot use NaN as an upper bound in " + ClassicHistogramBuckets.class.getSimpleName()); +- } +- if (counts[i] < 0) { +- throw new IllegalArgumentException( +- "Counts in " + ClassicHistogramBuckets.class.getSimpleName() + " cannot be negative."); +- } ++ checkArgument( ++ !Double.isNaN(upperBounds[i]), ++ "Cannot use NaN as an upper bound in %s", ++ ClassicHistogramBuckets.class.getSimpleName()); ++ checkArgument( ++ counts[i] >= 0, ++ "Counts in %s cannot be negative.", ++ ClassicHistogramBuckets.class.getSimpleName()); + if (i > 0) { +- if (upperBounds[i - 1] == upperBounds[i]) { +- throw new IllegalArgumentException("Duplicate upper bound " + upperBounds[i]); +- } ++ checkArgument( ++ upperBounds[i - 1] != upperBounds[i], "Duplicate upper bound %s", upperBounds[i]); + } + } + } +@@ -183,7 +180,7 @@ public class ClassicHistogramBuckets implements Iterable + for (int i = 0; i < upperBounds.length; i++) { + result.add(new ClassicHistogramBucket(upperBounds[i], counts[i])); + } +- return Collections.unmodifiableList(result); ++ return unmodifiableList(result); + } + + @Override +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/CounterSnapshot.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/CounterSnapshot.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.ArrayList; + import java.util.Collection; + import java.util.List; +@@ -19,8 +21,8 @@ public class CounterSnapshot extends MetricSnapshot { + super(metadata, dataPoints); + } + +- @SuppressWarnings("unchecked") + @Override ++ @SuppressWarnings("unchecked") + public List getDataPoints() { + return (List) dataPoints; + } +@@ -74,9 +76,7 @@ public class CounterSnapshot extends MetricSnapshot { + } + + protected void validate() { +- if (value < 0.0) { +- throw new IllegalArgumentException(value + ": counters cannot have a negative value"); +- } ++ checkArgument(value >= 0.0, "%s: counters cannot have a negative value", value); + } + + public static Builder builder() { +@@ -108,9 +108,7 @@ public class CounterSnapshot extends MetricSnapshot { + } + + public CounterDataPointSnapshot build() { +- if (value == null) { +- throw new IllegalArgumentException("Missing required field: value is null."); +- } ++ checkArgument(value != null, "Missing required field: value is null."); + return new CounterDataPointSnapshot( + value, labels, exemplar, createdTimestampMillis, scrapeTimestampMillis); + } +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/DataPointSnapshot.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/DataPointSnapshot.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + @SuppressWarnings("this-escape") + public abstract class DataPointSnapshot { + private final Labels labels; +@@ -15,25 +17,20 @@ public abstract class DataPointSnapshot { + } + + private void validate() { +- if (labels == null) { +- throw new IllegalArgumentException( +- "Labels cannot be null. Use Labels.EMPTY if there are no labels."); +- } +- if (createdTimestampMillis < 0) { +- throw new IllegalArgumentException( +- "Created timestamp cannot be negative. " +- + "Use 0 if the metric doesn't have a created timestamp."); +- } +- if (scrapeTimestampMillis < 0) { +- throw new IllegalArgumentException( +- "Scrape timestamp cannot be negative. " +- + "Use 0 to indicate that the Prometheus server should set the scrape timestamp."); +- } ++ checkArgument( ++ labels != null, "Labels cannot be null. Use Labels.EMPTY if there are no labels."); ++ checkArgument( ++ createdTimestampMillis >= 0, ++ "Created timestamp cannot be negative. " ++ + "Use 0 if the metric doesn't have a created timestamp."); ++ checkArgument( ++ scrapeTimestampMillis >= 0, ++ "Scrape timestamp cannot be negative. " ++ + "Use 0 to indicate that the Prometheus server should set the scrape timestamp."); + if (hasCreatedTimestamp() && hasScrapeTimestamp()) { +- if (scrapeTimestampMillis < createdTimestampMillis) { +- throw new IllegalArgumentException( +- "The scrape timestamp cannot be before the created timestamp"); +- } ++ checkArgument( ++ scrapeTimestampMillis >= createdTimestampMillis, ++ "The scrape timestamp cannot be before the created timestamp"); + } + } + +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/Exemplar.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/Exemplar.java +@@ -1,5 +1,8 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkState; ++import static java.util.Objects.requireNonNull; ++ + /** Immutable representation of an Exemplar. */ + public class Exemplar { + +@@ -24,9 +27,7 @@ public class Exemplar { + * available. + */ + public Exemplar(double value, Labels labels, long timestampMillis) { +- if (labels == null) { +- throw new NullPointerException("Labels cannot be null. Use Labels.EMPTY."); +- } ++ requireNonNull(labels, "Labels cannot be null. Use Labels.EMPTY."); + this.value = value; + this.labels = labels; + this.timestampMillis = timestampMillis; +@@ -83,9 +84,7 @@ public class Exemplar { + } + + public Builder labels(Labels labels) { +- if (labels == null) { +- throw new NullPointerException(); +- } ++ requireNonNull(labels); + this.labels = labels; + return this; + } +@@ -99,9 +98,7 @@ public class Exemplar { + * @throws IllegalStateException if {@link #value(double)} wasn't called. + */ + public Exemplar build() { +- if (value == null) { +- throw new IllegalStateException("cannot build an Exemplar without a value"); +- } ++ checkState(value != null, "cannot build an Exemplar without a value"); + Labels allLabels; + if (traceId != null && spanId != null) { + allLabels = Labels.of(TRACE_ID, traceId, SPAN_ID, spanId); +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/Exemplars.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/Exemplars.java +@@ -1,9 +1,12 @@ + package io.prometheus.metrics.model.snapshots; + ++import static java.util.Collections.unmodifiableList; ++import static java.util.Objects.requireNonNull; ++ ++import com.google.common.collect.ImmutableList; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.Collection; +-import java.util.Collections; + import java.util.Iterator; + import java.util.List; + +@@ -16,19 +19,17 @@ import java.util.List; + public class Exemplars implements Iterable { + + /** EMPTY means no Exemplars. */ +- public static final Exemplars EMPTY = new Exemplars(Collections.emptyList()); ++ public static final Exemplars EMPTY = new Exemplars(ImmutableList.of()); + + private final List exemplars; + + private Exemplars(Collection exemplars) { + List copy = new ArrayList<>(exemplars.size()); + for (Exemplar exemplar : exemplars) { +- if (exemplar == null) { +- throw new NullPointerException("Illegal null value in Exemplars"); +- } ++ requireNonNull(exemplar, "Illegal null value in Exemplars"); + copy.add(exemplar); + } +- this.exemplars = Collections.unmodifiableList(copy); ++ this.exemplars = unmodifiableList(copy); + } + + /** +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/GaugeSnapshot.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/GaugeSnapshot.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.ArrayList; + import java.util.Collection; + import java.util.List; +@@ -18,8 +20,8 @@ public final class GaugeSnapshot extends MetricSnapshot { + super(metadata, data); + } + +- @SuppressWarnings("unchecked") + @Override ++ @SuppressWarnings("unchecked") + public List getDataPoints() { + return (List) dataPoints; + } +@@ -86,9 +88,7 @@ public final class GaugeSnapshot extends MetricSnapshot { + } + + public GaugeDataPointSnapshot build() { +- if (value == null) { +- throw new IllegalArgumentException("Missing required field: value is null."); +- } ++ checkArgument(value != null, "Missing required field: value is null."); + return new GaugeDataPointSnapshot(value, labels, exemplar, scrapeTimestampMillis); + } + +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/HistogramSnapshot.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/HistogramSnapshot.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.ArrayList; + import java.util.Collection; + import java.util.List; +@@ -39,8 +41,8 @@ public final class HistogramSnapshot extends MetricSnapshot { + return gaugeHistogram; + } + +- @SuppressWarnings("unchecked") + @Override ++ @SuppressWarnings("unchecked") + public List getDataPoints() { + return (List) dataPoints; + } +@@ -268,15 +270,11 @@ public final class HistogramSnapshot extends MetricSnapshot { + long nativeCount = + calculateNativeCount( + nativeZeroCount, nativeBucketsForPositiveValues, nativeBucketsForNegativeValues); +- if (classicCount != nativeCount) { +- throw new IllegalArgumentException( +- "Inconsistent observation count: If a histogram has both classic and native " +- + "data the observation count must be the same. Classic count is " +- + classicCount +- + " but native count is " +- + nativeCount +- + "."); +- } ++ checkArgument( ++ classicCount == nativeCount, ++ "Inconsistent observation count: If a histogram has both classic and native data the observation count must be the same. Classic count is %s but native count is %s.", ++ classicCount, ++ nativeCount); + return classicCount; + } + } +@@ -354,27 +352,22 @@ public final class HistogramSnapshot extends MetricSnapshot { + + private void validate() { + for (Label label : getLabels()) { +- if (label.getName().equals("le")) { +- throw new IllegalArgumentException("le is a reserved label name for histograms"); +- } +- } +- if (nativeSchema == CLASSIC_HISTOGRAM && classicBuckets.isEmpty()) { +- throw new IllegalArgumentException( +- "Histogram buckets cannot be empty, must at least have the +Inf bucket."); ++ checkArgument(!label.getName().equals("le"), "le is a reserved label name for histograms"); + } ++ checkArgument( ++ nativeSchema != CLASSIC_HISTOGRAM || !classicBuckets.isEmpty(), ++ "Histogram buckets cannot be empty, must at least have the +Inf bucket."); + if (nativeSchema != CLASSIC_HISTOGRAM) { +- if (nativeSchema < -4 || nativeSchema > 8) { +- throw new IllegalArgumentException( +- nativeSchema + ": illegal schema. Expecting number in [-4, 8]."); +- } +- if (nativeZeroCount < 0) { +- throw new IllegalArgumentException( +- nativeZeroCount + ": nativeZeroCount cannot be negative"); +- } +- if (Double.isNaN(nativeZeroThreshold) || nativeZeroThreshold < 0) { +- throw new IllegalArgumentException( +- nativeZeroThreshold + ": illegal nativeZeroThreshold. Must be >= 0."); +- } ++ checkArgument( ++ nativeSchema >= -4 && nativeSchema <= 8, ++ "%s: illegal schema. Expecting number in [-4, 8].", ++ nativeSchema); ++ checkArgument( ++ nativeZeroCount >= 0, "%s: nativeZeroCount cannot be negative", nativeZeroCount); ++ checkArgument( ++ !Double.isNaN(nativeZeroThreshold) && nativeZeroThreshold >= 0, ++ "%s: illegal nativeZeroThreshold. Must be >= 0.", ++ nativeZeroThreshold); + } + } + +@@ -431,10 +424,9 @@ public final class HistogramSnapshot extends MetricSnapshot { + } + + public HistogramDataPointSnapshot build() { +- if (nativeSchema == CLASSIC_HISTOGRAM && classicHistogramBuckets.isEmpty()) { +- throw new IllegalArgumentException( +- "One of nativeSchema and classicHistogramBuckets is required."); +- } ++ checkArgument( ++ nativeSchema != CLASSIC_HISTOGRAM || !classicHistogramBuckets.isEmpty(), ++ "One of nativeSchema and classicHistogramBuckets is required."); + return new HistogramDataPointSnapshot( + classicHistogramBuckets, + nativeSchema, +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/InfoSnapshot.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/InfoSnapshot.java +@@ -1,5 +1,7 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; ++ + import java.util.ArrayList; + import java.util.Collection; + import java.util.List; +@@ -17,13 +19,11 @@ public final class InfoSnapshot extends MetricSnapshot { + */ + public InfoSnapshot(MetricMetadata metadata, Collection data) { + super(metadata, data); +- if (metadata.hasUnit()) { +- throw new IllegalArgumentException("An Info metric cannot have a unit."); +- } ++ checkArgument(!metadata.hasUnit(), "An Info metric cannot have a unit."); + } + +- @SuppressWarnings("unchecked") + @Override ++ @SuppressWarnings("unchecked") + public List getDataPoints() { + return (List) dataPoints; + } +--- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/Labels.java ++++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/Labels.java +@@ -1,11 +1,12 @@ + package io.prometheus.metrics.model.snapshots; + ++import static com.google.common.base.Preconditions.checkArgument; + import static io.prometheus.metrics.model.snapshots.PrometheusNaming.isValidLabelName; + import static io.prometheus.metrics.model.snapshots.PrometheusNaming.prometheusName; ++import static java.util.Collections.unmodifiableList; + + import java.util.ArrayList; + import java.util.Arrays; +-import java.util.Collections; + import java.util.Iterator; + import java.util.List; + import java.util.stream.Stream; +@@ -52,9 +53,7 @@ public final class Labels implements Comparable, Iterable