From c3deb5186404fe3093836a2e00c019200d93cc78 Mon Sep 17 00:00:00 2001 From: robsunday Date: Fri, 22 Nov 2024 10:40:47 +0100 Subject: [PATCH 01/53] New metrics validation framework fundamentals. --- .../target_systems/JvmIntegrationTest.java | 57 ++---- .../target_systems/MetricsVerifier.java | 174 ++++++++++++++++++ .../TargetSystemIntegrationTest.java | 35 +++- 3 files changed, 228 insertions(+), 38 deletions(-) create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index d22f27496..4e68a16cd 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -5,10 +5,6 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGauge; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertTypedGauge; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertTypedSum; - import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import io.opentelemetry.contrib.jmxscraper.TestAppContainer; import java.nio.file.Path; @@ -36,7 +32,7 @@ protected JmxScraperContainer customizeScraperContainer( } @Override - protected void verifyMetrics() { + protected MetricsVerifier createMetricsVerifier() { // those values depend on the JVM GC configured List gcLabels = Arrays.asList( @@ -48,43 +44,30 @@ protected void verifyMetrics() { "PS Survivor Space"); List gcCollectionLabels = Arrays.asList("PS MarkSweep", "PS Scavenge"); - waitAndAssertMetrics( - metric -> assertGauge(metric, "jvm.classes.loaded", "number of loaded classes", "1"), - metric -> - assertTypedSum( - metric, + return MetricsVerifier.create() + .assertGauge("jvm.classes.loaded", "number of loaded classes", "1") + .assertTypedSum( "jvm.gc.collections.count", "total number of collections that have occurred", "1", - gcCollectionLabels), - metric -> - assertTypedSum( - metric, + gcCollectionLabels) + .assertTypedSum( "jvm.gc.collections.elapsed", "the approximate accumulated collection elapsed time in milliseconds", "ms", - gcCollectionLabels), - metric -> assertGauge(metric, "jvm.memory.heap.committed", "current heap usage", "by"), - metric -> assertGauge(metric, "jvm.memory.heap.init", "current heap usage", "by"), - metric -> assertGauge(metric, "jvm.memory.heap.max", "current heap usage", "by"), - metric -> assertGauge(metric, "jvm.memory.heap.used", "current heap usage", "by"), - metric -> - assertGauge(metric, "jvm.memory.nonheap.committed", "current non-heap usage", "by"), - metric -> assertGauge(metric, "jvm.memory.nonheap.init", "current non-heap usage", "by"), - metric -> assertGauge(metric, "jvm.memory.nonheap.max", "current non-heap usage", "by"), - metric -> assertGauge(metric, "jvm.memory.nonheap.used", "current non-heap usage", "by"), - metric -> - assertTypedGauge( - metric, "jvm.memory.pool.committed", "current memory pool usage", "by", gcLabels), - metric -> - assertTypedGauge( - metric, "jvm.memory.pool.init", "current memory pool usage", "by", gcLabels), - metric -> - assertTypedGauge( - metric, "jvm.memory.pool.max", "current memory pool usage", "by", gcLabels), - metric -> - assertTypedGauge( - metric, "jvm.memory.pool.used", "current memory pool usage", "by", gcLabels), - metric -> assertGauge(metric, "jvm.threads.count", "number of threads", "1")); + gcCollectionLabels) + .assertGauge("jvm.memory.heap.committed", "current heap usage", "by") + .assertGauge("jvm.memory.heap.init", "current heap usage", "by") + .assertGauge("jvm.memory.heap.max", "current heap usage", "by") + .assertGauge("jvm.memory.heap.used", "current heap usage", "by") + .assertGauge("jvm.memory.nonheap.committed", "current non-heap usage", "by") + .assertGauge("jvm.memory.nonheap.init", "current non-heap usage", "by") + .assertGauge("jvm.memory.nonheap.max", "current non-heap usage", "by") + .assertGauge("jvm.memory.nonheap.used", "current non-heap usage", "by") + .assertTypedGauge("jvm.memory.pool.committed", "current memory pool usage", "by", gcLabels) + .assertTypedGauge("jvm.memory.pool.init", "current memory pool usage", "by", gcLabels) + .assertTypedGauge("jvm.memory.pool.max", "current memory pool usage", "by", gcLabels) + .assertTypedGauge("jvm.memory.pool.used", "current memory pool usage", "by", gcLabels) + .assertGauge("jvm.threads.count", "number of threads", "1"); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java new file mode 100644 index 000000000..84fc37352 --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -0,0 +1,174 @@ +package io.opentelemetry.contrib.jmxscraper.target_systems; + +import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.metrics.v1.Metric; +import io.opentelemetry.proto.metrics.v1.NumberDataPoint; +import org.assertj.core.api.MapAssert; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.assertj.core.api.Assertions.fail; + +public class MetricsVerifier { + private static final String METRIC_VERIFICATION_FAILURE_MESSAGE = "Verification of %s metric failed"; + + private final Map> assertions = new HashMap<>(); + private boolean strictMode = true; + + private MetricsVerifier() {} + + /** + * Create instance of MetricsVerifier configured to fail verification if any metric was not verified + * because there is no assertion defined for it. This behavior can be changed by calling allowingExtraMetrics() + * method. + * + * @return new instance of MetricsVerifier + * @see #allowExtraMetrics() + */ + public static MetricsVerifier create() { + return new MetricsVerifier(); + } + + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public MetricsVerifier allowExtraMetrics() { + strictMode = false; + return this; + } + + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public MetricsVerifier assertGauge(String metricName, String description, String unit) { + assertions.put(metricName, metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithGauge(metric); + assertThat(metric.getGauge().getDataPointsList()) + .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); //TODO ????? + }); + + return this; + } + + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public MetricsVerifier assertTypedSum( + String metricName, String description, String unit, List types) { + assertions.put(metricName, metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithSum(metric); + assertTypedPoints(metricName, metric.getSum().getDataPointsList(), types); + }); + + return this; + } + + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public MetricsVerifier assertTypedGauge( + String metricName, String description, String unit, List types) { + assertions.put(metricName, metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithGauge(metric); + assertTypedPoints(metricName, metric.getGauge().getDataPointsList(), types); + }); + + return this; + } + + + public void verify(List metrics) { + Set unverifiedMetrics = new HashSet<>(); + Set skippedAssertions = assertions.keySet(); + + for (Metric metric : metrics) { + String metricName = metric.getName(); + Consumer assertion = assertions.get(metricName); + + if (assertion != null) { + assertion.accept(metric); + skippedAssertions.remove(metricName); + } else { + unverifiedMetrics.add(metricName); + } + } + + if (!skippedAssertions.isEmpty()) { + fail("The following metrics was expected but not received: " + skippedAssertions); + } + if (strictMode && !unverifiedMetrics.isEmpty()) { + fail("The following metrics was received but not verified: " + unverifiedMetrics); + } + } + + + private static void assertMetricWithGauge(Metric metric) { + assertThat(metric.hasGauge()).withFailMessage("Metric with gauge expected").isTrue(); + } + + private static void assertMetricWithSum(Metric metric) { + assertThat(metric.hasSum()).withFailMessage("Metric with sum expected").isTrue(); + } + +// private static void assertMetricWithSum(Metric metric, boolean isMonotonic) { +// assertMetricWithSum(metric); +// assertThat(metric.getSum().getIsMonotonic()) +// .withFailMessage("Metric should " + (isMonotonic ? "" : "not ") + "be monotonic") +// .isEqualTo(isMonotonic); +// } + + private static void assertDescription(Metric metric, String expectedDescription) { + assertThat(metric.getDescription()) + .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metric.getName()) + .withFailMessage("\nExpected description: %s\n Actual description: %s", expectedDescription, metric.getDescription()) + .isEqualTo(expectedDescription); + } + + private static void assertUnit(Metric metric, String expectedUnit) { + assertThat(metric.getUnit()) + .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metric.getName()) + .withFailMessage("\nExpected unit: %s\n Actual unit: %s", expectedUnit, metric.getUnit()) + .isEqualTo(expectedUnit); + } + + @SuppressWarnings("unchecked") + private static void assertTypedPoints(String metricName, List points, List types) { + Consumer>[] assertions = + types.stream() + .map( + type -> + (Consumer>) + attrs -> attrs.containsOnly(entry("name", type))) + .toArray(Consumer[]::new); + + assertAttributedPoints(metricName, points, assertions); + } + + @SuppressWarnings("unchecked") + private static void assertAttributedPoints( + String metricName, + List points, + Consumer>... attributeGroupAssertions) { + Consumer>[] assertions = + Arrays.stream(attributeGroupAssertions) + .map(assertion -> (Consumer>) m -> assertion.accept(assertThat(m))) + .toArray(Consumer[]::new); + + assertThat(points) + .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metricName) + .extracting( + numberDataPoint -> + numberDataPoint.getAttributesList().stream() + .collect( + Collectors.toMap( + KeyValue::getKey, keyValue -> keyValue.getValue().getStringValue()))) + .satisfiesExactlyInAnyOrder(assertions); + } +} diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java index 064e4f021..847000753 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java @@ -125,6 +125,7 @@ void endToEndTest(@TempDir Path tmpDir) { verifyMetrics(); } + // TODO: This implementation is DEPRECATED and will be removed once all integration tests are migrated to MetricsVerifier protected void waitAndAssertMetrics(Iterable> assertions) { await() .atMost(Duration.ofSeconds(30)) @@ -154,13 +155,45 @@ protected void waitAndAssertMetrics(Iterable> assertions) { }); } + // TODO: This implementation is DEPRECATED and will be removed once all integration tests are migrated to MetricsVerifier @SafeVarargs @SuppressWarnings("varargs") protected final void waitAndAssertMetrics(Consumer... assertions) { waitAndAssertMetrics(Arrays.asList(assertions)); } - protected abstract void verifyMetrics(); + protected void verifyMetrics() { + await() + .atMost(Duration.ofSeconds(5)) // TODO: Revert to 30 + .untilAsserted( + () -> { + List receivedMetrics = otlpServer.getMetrics(); + assertThat(receivedMetrics).describedAs("No metric received").isNotEmpty(); + + List metrics = + receivedMetrics.stream() + .map(ExportMetricsServiceRequest::getResourceMetricsList) + .flatMap(rm -> rm.stream().map(ResourceMetrics::getScopeMetricsList)) + .flatMap(Collection::stream) + .filter( + // TODO: disabling batch span exporter might help remove unwanted metrics + sm -> sm.getScope().getName().equals("io.opentelemetry.jmx")) + .flatMap(sm -> sm.getMetricsList().stream()) + .collect(Collectors.toList()); + + assertThat(metrics) + .describedAs("metrics reported but none from JMX scraper") + .isNotEmpty(); + + MetricsVerifier metricsVerifier = createMetricsVerifier(); + metricsVerifier.verify(metrics); + }); + } + + // TODO: This method is going to be abstract once all integration tests are migrated to MetricsVerifier + protected MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create(); + } protected JmxScraperContainer customizeScraperContainer( JmxScraperContainer scraper, GenericContainer target, Path tempDir) { From fcf2bf8d12312e0417b630a642a0a37da546b55a Mon Sep 17 00:00:00 2001 From: robsunday Date: Fri, 22 Nov 2024 10:46:25 +0100 Subject: [PATCH 02/53] Spotless fixes --- .../target_systems/JvmIntegrationTest.java | 16 ++-- .../target_systems/MetricsVerifier.java | 90 +++++++++++-------- .../TargetSystemIntegrationTest.java | 11 ++- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index 4e68a16cd..95433e83e 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -47,15 +47,15 @@ protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() .assertGauge("jvm.classes.loaded", "number of loaded classes", "1") .assertTypedSum( - "jvm.gc.collections.count", - "total number of collections that have occurred", - "1", - gcCollectionLabels) + "jvm.gc.collections.count", + "total number of collections that have occurred", + "1", + gcCollectionLabels) .assertTypedSum( - "jvm.gc.collections.elapsed", - "the approximate accumulated collection elapsed time in milliseconds", - "ms", - gcCollectionLabels) + "jvm.gc.collections.elapsed", + "the approximate accumulated collection elapsed time in milliseconds", + "ms", + gcCollectionLabels) .assertGauge("jvm.memory.heap.committed", "current heap usage", "by") .assertGauge("jvm.memory.heap.init", "current heap usage", "by") .assertGauge("jvm.memory.heap.max", "current heap usage", "by") diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 84fc37352..37f42b6ac 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -1,10 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.contrib.jmxscraper.target_systems; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.assertj.core.api.Assertions.fail; + import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; import io.opentelemetry.proto.metrics.v1.NumberDataPoint; -import org.assertj.core.api.MapAssert; - import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -13,13 +20,11 @@ import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.assertj.core.api.Assertions.fail; +import org.assertj.core.api.MapAssert; public class MetricsVerifier { - private static final String METRIC_VERIFICATION_FAILURE_MESSAGE = "Verification of %s metric failed"; + private static final String METRIC_VERIFICATION_FAILURE_MESSAGE = + "Verification of %s metric failed"; private final Map> assertions = new HashMap<>(); private boolean strictMode = true; @@ -27,9 +32,9 @@ public class MetricsVerifier { private MetricsVerifier() {} /** - * Create instance of MetricsVerifier configured to fail verification if any metric was not verified - * because there is no assertion defined for it. This behavior can be changed by calling allowingExtraMetrics() - * method. + * Create instance of MetricsVerifier configured to fail verification if any metric was not + * verified because there is no assertion defined for it. This behavior can be changed by calling + * allowingExtraMetrics() method. * * @return new instance of MetricsVerifier * @see #allowExtraMetrics() @@ -46,13 +51,15 @@ public MetricsVerifier allowExtraMetrics() { @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertGauge(String metricName, String description, String unit) { - assertions.put(metricName, metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithGauge(metric); - assertThat(metric.getGauge().getDataPointsList()) - .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); //TODO ????? - }); + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithGauge(metric); + assertThat(metric.getGauge().getDataPointsList()) + .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); + }); return this; } @@ -60,12 +67,14 @@ public MetricsVerifier assertGauge(String metricName, String description, String @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertTypedSum( String metricName, String description, String unit, List types) { - assertions.put(metricName, metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithSum(metric); - assertTypedPoints(metricName, metric.getSum().getDataPointsList(), types); - }); + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithSum(metric); + assertTypedPoints(metricName, metric.getSum().getDataPointsList(), types); + }); return this; } @@ -73,17 +82,18 @@ public MetricsVerifier assertTypedSum( @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertTypedGauge( String metricName, String description, String unit, List types) { - assertions.put(metricName, metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithGauge(metric); - assertTypedPoints(metricName, metric.getGauge().getDataPointsList(), types); - }); + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithGauge(metric); + assertTypedPoints(metricName, metric.getGauge().getDataPointsList(), types); + }); return this; } - public void verify(List metrics) { Set unverifiedMetrics = new HashSet<>(); Set skippedAssertions = assertions.keySet(); @@ -108,7 +118,6 @@ public void verify(List metrics) { } } - private static void assertMetricWithGauge(Metric metric) { assertThat(metric.hasGauge()).withFailMessage("Metric with gauge expected").isTrue(); } @@ -117,17 +126,19 @@ private static void assertMetricWithSum(Metric metric) { assertThat(metric.hasSum()).withFailMessage("Metric with sum expected").isTrue(); } -// private static void assertMetricWithSum(Metric metric, boolean isMonotonic) { -// assertMetricWithSum(metric); -// assertThat(metric.getSum().getIsMonotonic()) -// .withFailMessage("Metric should " + (isMonotonic ? "" : "not ") + "be monotonic") -// .isEqualTo(isMonotonic); -// } + // private static void assertMetricWithSum(Metric metric, boolean isMonotonic) { + // assertMetricWithSum(metric); + // assertThat(metric.getSum().getIsMonotonic()) + // .withFailMessage("Metric should " + (isMonotonic ? "" : "not ") + "be monotonic") + // .isEqualTo(isMonotonic); + // } private static void assertDescription(Metric metric, String expectedDescription) { assertThat(metric.getDescription()) .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metric.getName()) - .withFailMessage("\nExpected description: %s\n Actual description: %s", expectedDescription, metric.getDescription()) + .withFailMessage( + "\nExpected description: %s\n Actual description: %s", + expectedDescription, metric.getDescription()) .isEqualTo(expectedDescription); } @@ -139,7 +150,8 @@ private static void assertUnit(Metric metric, String expectedUnit) { } @SuppressWarnings("unchecked") - private static void assertTypedPoints(String metricName, List points, List types) { + private static void assertTypedPoints( + String metricName, List points, List types) { Consumer>[] assertions = types.stream() .map( diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java index 847000753..2cd94cdc0 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java @@ -125,7 +125,8 @@ void endToEndTest(@TempDir Path tmpDir) { verifyMetrics(); } - // TODO: This implementation is DEPRECATED and will be removed once all integration tests are migrated to MetricsVerifier + // TODO: This implementation is DEPRECATED and will be removed once all integration tests are + // migrated to MetricsVerifier protected void waitAndAssertMetrics(Iterable> assertions) { await() .atMost(Duration.ofSeconds(30)) @@ -155,7 +156,8 @@ protected void waitAndAssertMetrics(Iterable> assertions) { }); } - // TODO: This implementation is DEPRECATED and will be removed once all integration tests are migrated to MetricsVerifier + // TODO: This implementation is DEPRECATED and will be removed once all integration tests are + // migrated to MetricsVerifier @SafeVarargs @SuppressWarnings("varargs") protected final void waitAndAssertMetrics(Consumer... assertions) { @@ -164,7 +166,7 @@ protected final void waitAndAssertMetrics(Consumer... assertions) { protected void verifyMetrics() { await() - .atMost(Duration.ofSeconds(5)) // TODO: Revert to 30 + .atMost(Duration.ofSeconds(30)) .untilAsserted( () -> { List receivedMetrics = otlpServer.getMetrics(); @@ -190,7 +192,8 @@ protected void verifyMetrics() { }); } - // TODO: This method is going to be abstract once all integration tests are migrated to MetricsVerifier + // TODO: This method is going to be abstract once all integration tests are migrated to + // MetricsVerifier protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create(); } From d833450f0004072fedc2199e44f9827a31e5c748 Mon Sep 17 00:00:00 2001 From: robsunday Date: Mon, 25 Nov 2024 09:21:37 +0100 Subject: [PATCH 03/53] Improved check for not received metrics --- .../target_systems/MetricsVerifier.java | 104 +++++++++++++++--- .../TargetSystemIntegrationTest.java | 2 +- 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 37f42b6ac..20ed52c7f 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -64,6 +64,59 @@ public MetricsVerifier assertGauge(String metricName, String description, String return this; } + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public MetricsVerifier assertCounter(String metricName, String description, String unit) { + return assertSum(metricName, description, unit, /* isMonotonic= */ true); + } + + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public MetricsVerifier assertUpDownCounter(String metricName, String description, String unit) { + return assertSum(metricName, description, unit, /* isMonotonic= */ false); + } + + @SafeVarargs + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public final MetricsVerifier assertCounterWithAttributes( + String metricName, + String description, + String unit, + Consumer>... attributeGroupAssertions) { + return assertSumWithAttributes( + metricName, description, unit, /* isMonotonic= */ true, attributeGroupAssertions); + } + + @SafeVarargs + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public final MetricsVerifier assertUpDownCounterWithAttributes( + String metricName, + String description, + String unit, + Consumer>... attributeGroupAssertions) { + return assertSumWithAttributes( + metricName, description, unit, /* isMonotonic= */ false, attributeGroupAssertions); + } + + @SafeVarargs + @SuppressWarnings("CanIgnoreReturnValueSuggester") + private final MetricsVerifier assertSumWithAttributes( + String metricName, + String description, + String unit, + boolean isMonotonic, + Consumer>... attributeGroupAssertions) { + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithSum(metric, isMonotonic); + assertAttributedPoints( + metricName, metric.getSum().getDataPointsList(), attributeGroupAssertions); + }); + + return this; + } + @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertTypedSum( String metricName, String description, String unit, List types) { @@ -72,7 +125,7 @@ public MetricsVerifier assertTypedSum( metric -> { assertDescription(metric, description); assertUnit(metric, unit); - assertMetricWithSum(metric); + assertMetricWithSum(metric, /* isMonotonic= */ true); assertTypedPoints(metricName, metric.getSum().getDataPointsList(), types); }); @@ -95,8 +148,9 @@ public MetricsVerifier assertTypedGauge( } public void verify(List metrics) { + verifyAllExpectedMetricsWereReceived(metrics); + Set unverifiedMetrics = new HashSet<>(); - Set skippedAssertions = assertions.keySet(); for (Metric metric : metrics) { String metricName = metric.getName(); @@ -104,35 +158,55 @@ public void verify(List metrics) { if (assertion != null) { assertion.accept(metric); - skippedAssertions.remove(metricName); } else { unverifiedMetrics.add(metricName); } } - if (!skippedAssertions.isEmpty()) { - fail("The following metrics was expected but not received: " + skippedAssertions); - } if (strictMode && !unverifiedMetrics.isEmpty()) { - fail("The following metrics was received but not verified: " + unverifiedMetrics); + fail("The following metrics were received but not verified: " + unverifiedMetrics); + } + } + + @SuppressWarnings("SystemOut") + private void verifyAllExpectedMetricsWereReceived(List metrics) { + Set receivedMetricNames = + metrics.stream().map(Metric::getName).collect(Collectors.toSet()); + Set assertionNames = new HashSet<>(assertions.keySet()); + + assertionNames.removeAll(receivedMetricNames); + if (!assertionNames.isEmpty()) { + fail("The following metrics were expected but not received: " + assertionNames); } } + @SuppressWarnings("CanIgnoreReturnValueSuggester") + private MetricsVerifier assertSum( + String metricName, String description, String unit, boolean isMonotonic) { + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithSum(metric, isMonotonic); + assertThat(metric.getSum().getDataPointsList()) + .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); + }); + + return this; + } + private static void assertMetricWithGauge(Metric metric) { assertThat(metric.hasGauge()).withFailMessage("Metric with gauge expected").isTrue(); } - private static void assertMetricWithSum(Metric metric) { + private static void assertMetricWithSum(Metric metric, boolean isMonotonic) { assertThat(metric.hasSum()).withFailMessage("Metric with sum expected").isTrue(); + assertThat(metric.getSum().getIsMonotonic()) + .withFailMessage((isMonotonic ? "Monotonic" : "Non monotonic") + " sum expected") + .isEqualTo(isMonotonic); } - // private static void assertMetricWithSum(Metric metric, boolean isMonotonic) { - // assertMetricWithSum(metric); - // assertThat(metric.getSum().getIsMonotonic()) - // .withFailMessage("Metric should " + (isMonotonic ? "" : "not ") + "be monotonic") - // .isEqualTo(isMonotonic); - // } - private static void assertDescription(Metric metric, String expectedDescription) { assertThat(metric.getDescription()) .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metric.getName()) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java index 2cd94cdc0..5a94b69af 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TargetSystemIntegrationTest.java @@ -165,6 +165,7 @@ protected final void waitAndAssertMetrics(Consumer... assertions) { } protected void verifyMetrics() { + MetricsVerifier metricsVerifier = createMetricsVerifier(); await() .atMost(Duration.ofSeconds(30)) .untilAsserted( @@ -187,7 +188,6 @@ protected void verifyMetrics() { .describedAs("metrics reported but none from JMX scraper") .isNotEmpty(); - MetricsVerifier metricsVerifier = createMetricsVerifier(); metricsVerifier.verify(metrics); }); } From 8cb96ad9bacad215ca26bed0c0e372ad3136bd64 Mon Sep 17 00:00:00 2001 From: robsunday Date: Mon, 25 Nov 2024 09:22:01 +0100 Subject: [PATCH 04/53] Cassandra integration test converted --- .../CassandraIntegrationTest.java | 175 +++++++----------- 1 file changed, 68 insertions(+), 107 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java index b909e62f7..76b206406 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java @@ -5,9 +5,6 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGauge; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSum; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSumWithAttributes; import static org.assertj.core.api.Assertions.entry; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; @@ -44,110 +41,74 @@ protected JmxScraperContainer customizeScraperContainer( } @Override - protected void verifyMetrics() { - waitAndAssertMetrics( - metric -> - assertGauge( - metric, - "cassandra.client.request.range_slice.latency.50p", - "Token range read request latency - 50th percentile", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.range_slice.latency.99p", - "Token range read request latency - 99th percentile", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.range_slice.latency.max", - "Maximum token range read request latency", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.read.latency.50p", - "Standard read request latency - 50th percentile", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.read.latency.99p", - "Standard read request latency - 99th percentile", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.read.latency.max", - "Maximum standard read request latency", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.write.latency.50p", - "Regular write request latency - 50th percentile", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.write.latency.99p", - "Regular write request latency - 99th percentile", - "us"), - metric -> - assertGauge( - metric, - "cassandra.client.request.write.latency.max", - "Maximum regular write request latency", - "us"), - metric -> - assertSum( - metric, - "cassandra.compaction.tasks.completed", - "Number of completed compactions since server [re]start", - "1"), - metric -> - assertGauge( - metric, - "cassandra.compaction.tasks.pending", - "Estimated number of compactions remaining to perform", - "1"), - metric -> - assertSum( - metric, - "cassandra.storage.load.count", - "Size of the on disk data size this node manages", - "by", - /* isMonotonic= */ false), - metric -> - assertSum( - metric, - "cassandra.storage.total_hints.count", - "Number of hint messages written to this node since [re]start", - "1"), - metric -> - assertSum( - metric, - "cassandra.storage.total_hints.in_progress.count", - "Number of hints attempting to be sent currently", - "1", - /* isMonotonic= */ false), - metric -> - assertSumWithAttributes( - metric, - "cassandra.client.request.count", - "Number of requests by operation", - "1", - attrs -> attrs.containsOnly(entry("operation", "RangeSlice")), - attrs -> attrs.containsOnly(entry("operation", "Read")), - attrs -> attrs.containsOnly(entry("operation", "Write"))), - metric -> - assertSumWithAttributes( - metric, - "cassandra.client.request.error.count", - "Number of request errors by operation", - "1", - getRequestErrorCountAttributes())); + protected MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create() + .assertGauge( + "cassandra.client.request.range_slice.latency.50p", + "Token range read request latency - 50th percentile", + "us") + .assertGauge( + "cassandra.client.request.range_slice.latency.99p", + "Token range read request latency - 99th percentile", + "us") + .assertGauge( + "cassandra.client.request.range_slice.latency.max", + "Maximum token range read request latency", + "us") + .assertGauge( + "cassandra.client.request.read.latency.50p", + "Standard read request latency - 50th percentile", + "us") + .assertGauge( + "cassandra.client.request.read.latency.99p", + "Standard read request latency - 99th percentile", + "us") + .assertGauge( + "cassandra.client.request.read.latency.max", + "Maximum standard read request latency", + "us") + .assertGauge( + "cassandra.client.request.write.latency.50p", + "Regular write request latency - 50th percentile", + "us") + .assertGauge( + "cassandra.client.request.write.latency.99p", + "Regular write request latency - 99th percentile", + "us") + .assertGauge( + "cassandra.client.request.write.latency.max", + "Maximum regular write request latency", + "us") + .assertCounter( + "cassandra.compaction.tasks.completed", + "Number of completed compactions since server [re]start", + "1") + .assertGauge( + "cassandra.compaction.tasks.pending", + "Estimated number of compactions remaining to perform", + "1") + .assertUpDownCounter( + "cassandra.storage.load.count", "Size of the on disk data size this node manages", "by") + .assertCounter( + "cassandra.storage.total_hints.count", + "Number of hint messages written to this node since [re]start", + "1") + .assertUpDownCounter( + "cassandra.storage.total_hints.in_progress.count", + "Number of hints attempting to be sent currently", + "1") + .assertCounterWithAttributes( + "cassandra.client.request.count", + "Number of requests by operation", + "1", + attrs -> attrs.containsOnly(entry("operation", "RangeSlice")), + attrs -> attrs.containsOnly(entry("operation", "Read")), + attrs -> attrs.containsOnly(entry("operation", "Write"))) + .assertCounterWithAttributes( + "cassandra.client.request.error.count", + "Number of request errors by operation", + "1", + getRequestErrorCountAttributes()); } @SuppressWarnings("unchecked") From f3bac7e8c2a365303b04fe907ad8d3bf8d0b6a2d Mon Sep 17 00:00:00 2001 From: robsunday Date: Mon, 25 Nov 2024 13:08:34 +0100 Subject: [PATCH 05/53] Fine tuning assertion messages. Method names improvement. --- .../target_systems/JvmIntegrationTest.java | 4 +- .../target_systems/MetricsVerifier.java | 48 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index 95433e83e..3acbbf82c 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -46,12 +46,12 @@ protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() .assertGauge("jvm.classes.loaded", "number of loaded classes", "1") - .assertTypedSum( + .assertTypedCounter( "jvm.gc.collections.count", "total number of collections that have occurred", "1", gcCollectionLabels) - .assertTypedSum( + .assertTypedCounter( "jvm.gc.collections.elapsed", "the approximate accumulated collection elapsed time in milliseconds", "ms", diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 20ed52c7f..5368603fa 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -96,29 +96,8 @@ public final MetricsVerifier assertUpDownCounterWithAttributes( metricName, description, unit, /* isMonotonic= */ false, attributeGroupAssertions); } - @SafeVarargs - @SuppressWarnings("CanIgnoreReturnValueSuggester") - private final MetricsVerifier assertSumWithAttributes( - String metricName, - String description, - String unit, - boolean isMonotonic, - Consumer>... attributeGroupAssertions) { - assertions.put( - metricName, - metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithSum(metric, isMonotonic); - assertAttributedPoints( - metricName, metric.getSum().getDataPointsList(), attributeGroupAssertions); - }); - - return this; - } - @SuppressWarnings("CanIgnoreReturnValueSuggester") - public MetricsVerifier assertTypedSum( + public MetricsVerifier assertTypedCounter( String metricName, String description, String unit, List types) { assertions.put( metricName, @@ -164,7 +143,7 @@ public void verify(List metrics) { } if (strictMode && !unverifiedMetrics.isEmpty()) { - fail("The following metrics were received but not verified: " + unverifiedMetrics); + fail("Metrics received but not verified because no assertion exists: " + unverifiedMetrics); } } @@ -176,7 +155,7 @@ private void verifyAllExpectedMetricsWereReceived(List metrics) { assertionNames.removeAll(receivedMetricNames); if (!assertionNames.isEmpty()) { - fail("The following metrics were expected but not received: " + assertionNames); + fail("Metrics expected but not received: " + assertionNames); } } @@ -196,6 +175,27 @@ private MetricsVerifier assertSum( return this; } + @SafeVarargs + @SuppressWarnings("CanIgnoreReturnValueSuggester") + private final MetricsVerifier assertSumWithAttributes( + String metricName, + String description, + String unit, + boolean isMonotonic, + Consumer>... attributeGroupAssertions) { + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithSum(metric, isMonotonic); + assertAttributedPoints( + metricName, metric.getSum().getDataPointsList(), attributeGroupAssertions); + }); + + return this; + } + private static void assertMetricWithGauge(Metric metric) { assertThat(metric.hasGauge()).withFailMessage("Metric with gauge expected").isTrue(); } From c9eb0a70e07e9f380225768ac30b5758a1105c71 Mon Sep 17 00:00:00 2001 From: robsunday Date: Mon, 25 Nov 2024 17:00:33 +0100 Subject: [PATCH 06/53] ActiveMqIntegrationTest converted --- .../ActiveMqIntegrationTest.java | 76 ++++++------------- .../target_systems/MetricsVerifier.java | 16 ++++ 2 files changed, 40 insertions(+), 52 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index 71374ba18..0c9d3a705 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -5,8 +5,6 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGaugeWithAttributes; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSumWithAttributes; import static org.assertj.core.api.Assertions.entry; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; @@ -39,112 +37,86 @@ protected JmxScraperContainer customizeScraperContainer( } @Override - protected void verifyMetrics() { - waitAndAssertMetrics( - metric -> - assertSumWithAttributes( - metric, + protected MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create() + .assertUpDownCounterWithAttributes( "activemq.consumer.count", "The number of consumers currently reading from the broker.", "{consumer}", - /* isMonotonic= */ false, attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertSumWithAttributes( - metric, + entry("broker", "localhost"))) + .assertUpDownCounterWithAttributes( "activemq.producer.count", "The number of producers currently attached to the broker.", "{producer}", - /* isMonotonic= */ false, attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertSumWithAttributes( - metric, + entry("broker", "localhost"))) + .assertUpDownCounterWithAttributes( "activemq.connection.count", "The total number of current connections.", "{connection}", - /* isMonotonic= */ false, - attrs -> attrs.containsOnly(entry("broker", "localhost"))), - metric -> - assertGaugeWithAttributes( - metric, + attrs -> attrs.containsOnly(entry("broker", "localhost"))) + .assertGaugeWithAttributes( "activemq.memory.usage", "The percentage of configured memory used.", "%", attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertGaugeWithAttributes( - metric, + entry("broker", "localhost"))) + .assertGaugeWithAttributes( "activemq.disk.store_usage", "The percentage of configured disk used for persistent messages.", "%", - attrs -> attrs.containsOnly(entry("broker", "localhost"))), - metric -> - assertGaugeWithAttributes( - metric, + attrs -> attrs.containsOnly(entry("broker", "localhost"))) + .assertGaugeWithAttributes( "activemq.disk.temp_usage", "The percentage of configured disk used for non-persistent messages.", "%", - attrs -> attrs.containsOnly(entry("broker", "localhost"))), - metric -> - assertSumWithAttributes( - metric, + attrs -> attrs.containsOnly(entry("broker", "localhost"))) + .assertUpDownCounterWithAttributes( "activemq.message.current", "The current number of messages waiting to be consumed.", "{message}", - /* isMonotonic= */ false, attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertSumWithAttributes( - metric, + entry("broker", "localhost"))) + .assertCounterWithAttributes( "activemq.message.expired", "The total number of messages not delivered because they expired.", "{message}", attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertSumWithAttributes( - metric, + entry("broker", "localhost"))) + .assertCounterWithAttributes( "activemq.message.enqueued", "The total number of messages received by the broker.", "{message}", attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertSumWithAttributes( - metric, + entry("broker", "localhost"))) + .assertCounterWithAttributes( "activemq.message.dequeued", "The total number of messages delivered to consumers.", "{message}", attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))), - metric -> - assertGaugeWithAttributes( - metric, + entry("broker", "localhost"))) + .assertGaugeWithAttributes( "activemq.message.wait_time.avg", "The average time a message was held on a destination.", "ms", attrs -> attrs.containsOnly( entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")))); + entry("broker", "localhost"))); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 5368603fa..cef2c2022 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -74,6 +74,22 @@ public MetricsVerifier assertUpDownCounter(String metricName, String description return assertSum(metricName, description, unit, /* isMonotonic= */ false); } + @SafeVarargs + @SuppressWarnings("CanIgnoreReturnValueSuggester") + public final MetricsVerifier assertGaugeWithAttributes(String metricName, String description, + String unit, Consumer>... attributeGroupAssertions) { + assertions.put( + metricName, + metric -> { + assertDescription(metric, description); + assertUnit(metric, unit); + assertMetricWithGauge(metric); + assertAttributedPoints(metricName, metric.getGauge().getDataPointsList(), attributeGroupAssertions); + }); + + return this; + } + @SafeVarargs @SuppressWarnings("CanIgnoreReturnValueSuggester") public final MetricsVerifier assertCounterWithAttributes( From 2c85c381df4348762292ec75e2f6e25a2574cc91 Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 26 Nov 2024 09:38:38 +0100 Subject: [PATCH 07/53] Spotless fix --- .../ActiveMqIntegrationTest.java | 156 +++++++++--------- .../target_systems/MetricsVerifier.java | 10 +- 2 files changed, 85 insertions(+), 81 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index 0c9d3a705..8b9ddd00f 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -40,83 +40,83 @@ protected JmxScraperContainer customizeScraperContainer( protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() .assertUpDownCounterWithAttributes( - "activemq.consumer.count", - "The number of consumers currently reading from the broker.", - "{consumer}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertUpDownCounterWithAttributes( - "activemq.producer.count", - "The number of producers currently attached to the broker.", - "{producer}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertUpDownCounterWithAttributes( - "activemq.connection.count", - "The total number of current connections.", - "{connection}", - attrs -> attrs.containsOnly(entry("broker", "localhost"))) - .assertGaugeWithAttributes( - "activemq.memory.usage", - "The percentage of configured memory used.", - "%", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertGaugeWithAttributes( - "activemq.disk.store_usage", - "The percentage of configured disk used for persistent messages.", - "%", - attrs -> attrs.containsOnly(entry("broker", "localhost"))) - .assertGaugeWithAttributes( - "activemq.disk.temp_usage", - "The percentage of configured disk used for non-persistent messages.", - "%", - attrs -> attrs.containsOnly(entry("broker", "localhost"))) - .assertUpDownCounterWithAttributes( - "activemq.message.current", - "The current number of messages waiting to be consumed.", - "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertCounterWithAttributes( - "activemq.message.expired", - "The total number of messages not delivered because they expired.", - "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertCounterWithAttributes( - "activemq.message.enqueued", - "The total number of messages received by the broker.", - "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertCounterWithAttributes( - "activemq.message.dequeued", - "The total number of messages delivered to consumers.", - "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) - .assertGaugeWithAttributes( - "activemq.message.wait_time.avg", - "The average time a message was held on a destination.", - "ms", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))); + "activemq.consumer.count", + "The number of consumers currently reading from the broker.", + "{consumer}", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertUpDownCounterWithAttributes( + "activemq.producer.count", + "The number of producers currently attached to the broker.", + "{producer}", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertUpDownCounterWithAttributes( + "activemq.connection.count", + "The total number of current connections.", + "{connection}", + attrs -> attrs.containsOnly(entry("broker", "localhost"))) + .assertGaugeWithAttributes( + "activemq.memory.usage", + "The percentage of configured memory used.", + "%", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertGaugeWithAttributes( + "activemq.disk.store_usage", + "The percentage of configured disk used for persistent messages.", + "%", + attrs -> attrs.containsOnly(entry("broker", "localhost"))) + .assertGaugeWithAttributes( + "activemq.disk.temp_usage", + "The percentage of configured disk used for non-persistent messages.", + "%", + attrs -> attrs.containsOnly(entry("broker", "localhost"))) + .assertUpDownCounterWithAttributes( + "activemq.message.current", + "The current number of messages waiting to be consumed.", + "{message}", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertCounterWithAttributes( + "activemq.message.expired", + "The total number of messages not delivered because they expired.", + "{message}", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertCounterWithAttributes( + "activemq.message.enqueued", + "The total number of messages received by the broker.", + "{message}", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertCounterWithAttributes( + "activemq.message.dequeued", + "The total number of messages delivered to consumers.", + "{message}", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .assertGaugeWithAttributes( + "activemq.message.wait_time.avg", + "The average time a message was held on a destination.", + "ms", + attrs -> + attrs.containsOnly( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index cef2c2022..db9e39c2f 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -76,15 +76,19 @@ public MetricsVerifier assertUpDownCounter(String metricName, String description @SafeVarargs @SuppressWarnings("CanIgnoreReturnValueSuggester") - public final MetricsVerifier assertGaugeWithAttributes(String metricName, String description, - String unit, Consumer>... attributeGroupAssertions) { + public final MetricsVerifier assertGaugeWithAttributes( + String metricName, + String description, + String unit, + Consumer>... attributeGroupAssertions) { assertions.put( metricName, metric -> { assertDescription(metric, description); assertUnit(metric, unit); assertMetricWithGauge(metric); - assertAttributedPoints(metricName, metric.getGauge().getDataPointsList(), attributeGroupAssertions); + assertAttributedPoints( + metricName, metric.getGauge().getDataPointsList(), attributeGroupAssertions); }); return this; From bd1947fd6c1b16a8ba4d99777e25e4006abd5690 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:23:32 +0100 Subject: [PATCH 08/53] introduce 'register' API --- .../target_systems/MetricsVerifier.java | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index db9e39c2f..4627bbaf3 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -49,9 +49,15 @@ public MetricsVerifier allowExtraMetrics() { return this; } + @CanIgnoreReturnValue + public MetricsVerifier register(String metricName, Consumer assertion) { + assertions.put(metricName, assertion); + return this; + }; + @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertGauge(String metricName, String description, String unit) { - assertions.put( + return register( metricName, metric -> { assertDescription(metric, description); @@ -60,8 +66,6 @@ public MetricsVerifier assertGauge(String metricName, String description, String assertThat(metric.getGauge().getDataPointsList()) .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); }); - - return this; } @SuppressWarnings("CanIgnoreReturnValueSuggester") @@ -81,7 +85,7 @@ public final MetricsVerifier assertGaugeWithAttributes( String description, String unit, Consumer>... attributeGroupAssertions) { - assertions.put( + return register( metricName, metric -> { assertDescription(metric, description); @@ -90,8 +94,6 @@ public final MetricsVerifier assertGaugeWithAttributes( assertAttributedPoints( metricName, metric.getGauge().getDataPointsList(), attributeGroupAssertions); }); - - return this; } @SafeVarargs @@ -119,7 +121,7 @@ public final MetricsVerifier assertUpDownCounterWithAttributes( @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertTypedCounter( String metricName, String description, String unit, List types) { - assertions.put( + return register( metricName, metric -> { assertDescription(metric, description); @@ -127,14 +129,12 @@ public MetricsVerifier assertTypedCounter( assertMetricWithSum(metric, /* isMonotonic= */ true); assertTypedPoints(metricName, metric.getSum().getDataPointsList(), types); }); - - return this; } @SuppressWarnings("CanIgnoreReturnValueSuggester") public MetricsVerifier assertTypedGauge( String metricName, String description, String unit, List types) { - assertions.put( + return register( metricName, metric -> { assertDescription(metric, description); @@ -142,8 +142,6 @@ public MetricsVerifier assertTypedGauge( assertMetricWithGauge(metric); assertTypedPoints(metricName, metric.getGauge().getDataPointsList(), types); }); - - return this; } public void verify(List metrics) { @@ -182,7 +180,7 @@ private void verifyAllExpectedMetricsWereReceived(List metrics) { @SuppressWarnings("CanIgnoreReturnValueSuggester") private MetricsVerifier assertSum( String metricName, String description, String unit, boolean isMonotonic) { - assertions.put( + return register( metricName, metric -> { assertDescription(metric, description); @@ -191,8 +189,6 @@ private MetricsVerifier assertSum( assertThat(metric.getSum().getDataPointsList()) .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); }); - - return this; } @SafeVarargs From 1e64f80ac4d2c650c4516a8ffd3d3990e9f99392 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:55:33 +0100 Subject: [PATCH 09/53] introduce dedicated assertThat for metrics --- .../jmxscraper/assertions/Assertions.java | 15 ++ .../jmxscraper/assertions/MetricAssert.java | 151 ++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java new file mode 100644 index 000000000..b25e6d792 --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java @@ -0,0 +1,15 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.jmxscraper.assertions; + +import io.opentelemetry.proto.metrics.v1.Metric; + +public class Assertions extends org.assertj.core.api.Assertions { + + public static MetricAssert assertThat(Metric metric) { + return new MetricAssert(metric); + } +} diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java new file mode 100644 index 000000000..40e763111 --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -0,0 +1,151 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.jmxscraper.assertions; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.metrics.v1.Metric; +import io.opentelemetry.proto.metrics.v1.NumberDataPoint; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import org.assertj.core.api.AbstractAssert; +import org.assertj.core.internal.Integers; +import org.assertj.core.internal.Iterables; +import org.assertj.core.internal.Objects; + +public class MetricAssert extends AbstractAssert { + + private static final Objects objects = Objects.instance(); + private static final Iterables iterables = Iterables.instance(); + private static final Integers integers = Integers.instance(); + + MetricAssert(Metric actual) { + super(actual, MetricAssert.class); + } + + @CanIgnoreReturnValue + public MetricAssert hasDescription(String description) { + isNotNull(); + + info.description("unexpected description for metric '%s'", actual.getName()); + objects.assertEqual(info, actual.getDescription(), description); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert hasUnit(String unit) { + isNotNull(); + + info.description("unexpected unit for metric '%s'", actual.getName()); + objects.assertEqual(info, actual.getUnit(), unit); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert isGauge() { + isNotNull(); + + info.description("gauge expected for metric '%s'", actual.getName()); + objects.assertEqual(info, actual.hasGauge(), true); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert hasSum(boolean monotonic) { + isNotNull(); + + info.description("sum expected for metric '%s'", actual.getName()); + objects.assertEqual(info, actual.hasSum(), true); + + String prefix = monotonic ? "monotonic" : "non-monotonic"; + info.description(prefix + " sum expected for metric '%s'", actual.getName()); + objects.assertEqual(info, actual.getSum().getIsMonotonic(), monotonic); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert isCounter() { + hasSum(true); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert isUpDownCounter() { + hasSum(false); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert hasDataPointsWithoutAttributes() { + isNotNull(); + + return checkDataPoints( + dataPoints -> { + dataPointsCommonCheck(dataPoints); + + // all data points must not have any attribute + for (NumberDataPoint dataPoint : dataPoints) { + info.description( + "no attribute expected on data point for metric '%s'", actual.getName()); + iterables.assertEmpty(info, dataPoint.getAttributesList()); + } + }); + } + + @CanIgnoreReturnValue + private MetricAssert checkDataPoints(Consumer> listConsumer) { + // in practice usually one set of data points is provided but the + // protobuf does not enforce that so we have to ensure checking at least one + int count = 0; + if (actual.hasGauge()) { + count++; + listConsumer.accept(actual.getGauge().getDataPointsList()); + } + if (actual.hasSum()) { + count++; + listConsumer.accept(actual.getSum().getDataPointsList()); + } + info.description("at least one set of data points expected for metric '%s'", actual.getName()); + integers.assertGreaterThan(info, count, 0); + return this; + } + + @CanIgnoreReturnValue + public MetricAssert hasTypedDataPoints(Collection types) { + return checkDataPoints( + dataPoints -> { + dataPointsCommonCheck(dataPoints); + + Set foundValues = new HashSet<>(); + for (NumberDataPoint dataPoint : dataPoints) { + List attributes = dataPoint.getAttributesList(); + + info.description( + "expected exactly one 'name' attribute for typed data point in metric '%s'", + actual.getName()); + iterables.assertHasSize(info, attributes, 1); + + objects.assertEqual(info, attributes.get(0).getKey(), "name"); + foundValues.add(attributes.get(0).getValue().getStringValue()); + } + info.description( + "missing or unexpected type attribute for metric '%s'", actual.getName()); + iterables.assertContainsExactlyInAnyOrder(info, foundValues, types.toArray()); + }); + } + + private void dataPointsCommonCheck(List dataPoints) { + info.description("unable to retrieve data points from metric '%s'", actual.getName()); + objects.assertNotNull(info, dataPoints); + + // at least one data point must be reported + info.description("at least one data point expected for metric '%s'", actual.getName()); + iterables.assertNotEmpty(info, dataPoints); + } +} From f7c6373c1f96b119d1aae928416adb2b0526112c Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:56:29 +0100 Subject: [PATCH 10/53] refactor metrics verifier --- .../target_systems/MetricsVerifier.java | 166 +++++++----------- 1 file changed, 65 insertions(+), 101 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 4627bbaf3..ff6b7c5d0 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -5,10 +5,11 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; +import static io.opentelemetry.contrib.jmxscraper.assertions.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.contrib.jmxscraper.assertions.MetricAssert; import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; import io.opentelemetry.proto.metrics.v1.NumberDataPoint; @@ -43,61 +44,82 @@ public static MetricsVerifier create() { return new MetricsVerifier(); } - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue public MetricsVerifier allowExtraMetrics() { strictMode = false; return this; } @CanIgnoreReturnValue - public MetricsVerifier register(String metricName, Consumer assertion) { + private MetricsVerifier registerAssert(String metricName, Consumer assertion) { assertions.put(metricName, assertion); return this; - }; + } - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue + public MetricsVerifier register(String metricName, Consumer assertion) { + assertions.put(metricName, metric -> assertion.accept(assertThat(metric))); + return this; + } + + // TODO: can now be inlined + @CanIgnoreReturnValue public MetricsVerifier assertGauge(String metricName, String description, String unit) { return register( metricName, - metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithGauge(metric); - assertThat(metric.getGauge().getDataPointsList()) - .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); - }); + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isGauge() + .hasDataPointsWithoutAttributes()); } - @SuppressWarnings("CanIgnoreReturnValueSuggester") + // TODO: can now be inlined + @CanIgnoreReturnValue public MetricsVerifier assertCounter(String metricName, String description, String unit) { - return assertSum(metricName, description, unit, /* isMonotonic= */ true); + return register( + metricName, + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isCounter() + .hasDataPointsWithoutAttributes()); } - @SuppressWarnings("CanIgnoreReturnValueSuggester") + // TODO: can now be inlined + @CanIgnoreReturnValue public MetricsVerifier assertUpDownCounter(String metricName, String description, String unit) { - return assertSum(metricName, description, unit, /* isMonotonic= */ false); + return register( + metricName, + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isUpDownCounter() + .hasDataPointsWithoutAttributes()); } @SafeVarargs - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue public final MetricsVerifier assertGaugeWithAttributes( String metricName, String description, String unit, Consumer>... attributeGroupAssertions) { - return register( + return registerAssert( metricName, metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithGauge(metric); + assertThat(metric).hasDescription(description).hasUnit(unit).isGauge(); + assertAttributedPoints( metricName, metric.getGauge().getDataPointsList(), attributeGroupAssertions); }); } @SafeVarargs - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue public final MetricsVerifier assertCounterWithAttributes( String metricName, String description, @@ -108,7 +130,7 @@ public final MetricsVerifier assertCounterWithAttributes( } @SafeVarargs - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue public final MetricsVerifier assertUpDownCounterWithAttributes( String metricName, String description, @@ -118,30 +140,30 @@ public final MetricsVerifier assertUpDownCounterWithAttributes( metricName, description, unit, /* isMonotonic= */ false, attributeGroupAssertions); } - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue public MetricsVerifier assertTypedCounter( String metricName, String description, String unit, List types) { - return register( + return registerAssert( metricName, - metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithSum(metric, /* isMonotonic= */ true); - assertTypedPoints(metricName, metric.getSum().getDataPointsList(), types); - }); + metric -> + assertThat(metric) + .hasDescription(description) + .hasUnit(unit) + .isCounter() + .hasTypedDataPoints(types)); } - @SuppressWarnings("CanIgnoreReturnValueSuggester") + @CanIgnoreReturnValue public MetricsVerifier assertTypedGauge( String metricName, String description, String unit, List types) { - return register( + return registerAssert( metricName, - metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithGauge(metric); - assertTypedPoints(metricName, metric.getGauge().getDataPointsList(), types); - }); + metric -> + assertThat(metric) + .hasDescription(description) + .hasUnit(unit) + .isGauge() + .hasTypedDataPoints(types)); } public void verify(List metrics) { @@ -177,20 +199,6 @@ private void verifyAllExpectedMetricsWereReceived(List metrics) { } } - @SuppressWarnings("CanIgnoreReturnValueSuggester") - private MetricsVerifier assertSum( - String metricName, String description, String unit, boolean isMonotonic) { - return register( - metricName, - metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithSum(metric, isMonotonic); - assertThat(metric.getSum().getDataPointsList()) - .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); - }); - } - @SafeVarargs @SuppressWarnings("CanIgnoreReturnValueSuggester") private final MetricsVerifier assertSumWithAttributes( @@ -199,58 +207,14 @@ private final MetricsVerifier assertSumWithAttributes( String unit, boolean isMonotonic, Consumer>... attributeGroupAssertions) { - assertions.put( + return registerAssert( metricName, metric -> { - assertDescription(metric, description); - assertUnit(metric, unit); - assertMetricWithSum(metric, isMonotonic); + assertThat(metric).hasDescription(description).hasUnit(unit).hasSum(isMonotonic); + assertAttributedPoints( metricName, metric.getSum().getDataPointsList(), attributeGroupAssertions); }); - - return this; - } - - private static void assertMetricWithGauge(Metric metric) { - assertThat(metric.hasGauge()).withFailMessage("Metric with gauge expected").isTrue(); - } - - private static void assertMetricWithSum(Metric metric, boolean isMonotonic) { - assertThat(metric.hasSum()).withFailMessage("Metric with sum expected").isTrue(); - assertThat(metric.getSum().getIsMonotonic()) - .withFailMessage((isMonotonic ? "Monotonic" : "Non monotonic") + " sum expected") - .isEqualTo(isMonotonic); - } - - private static void assertDescription(Metric metric, String expectedDescription) { - assertThat(metric.getDescription()) - .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metric.getName()) - .withFailMessage( - "\nExpected description: %s\n Actual description: %s", - expectedDescription, metric.getDescription()) - .isEqualTo(expectedDescription); - } - - private static void assertUnit(Metric metric, String expectedUnit) { - assertThat(metric.getUnit()) - .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metric.getName()) - .withFailMessage("\nExpected unit: %s\n Actual unit: %s", expectedUnit, metric.getUnit()) - .isEqualTo(expectedUnit); - } - - @SuppressWarnings("unchecked") - private static void assertTypedPoints( - String metricName, List points, List types) { - Consumer>[] assertions = - types.stream() - .map( - type -> - (Consumer>) - attrs -> attrs.containsOnly(entry("name", type))) - .toArray(Consumer[]::new); - - assertAttributedPoints(metricName, points, assertions); } @SuppressWarnings("unchecked") From b10a34079504799fdb32891d1558ed2844bbf7a9 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:12:17 +0100 Subject: [PATCH 11/53] add some javadoc & few comments --- .../jmxscraper/assertions/Assertions.java | 3 +++ .../jmxscraper/assertions/MetricAssert.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java index b25e6d792..4f02d9cb8 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java @@ -7,6 +7,9 @@ import io.opentelemetry.proto.metrics.v1.Metric; +/** + * Dedicated Assertj extension to provide convenient fluent API for metrics testing + */ public class Assertions extends org.assertj.core.api.Assertions { public static MetricAssert assertThat(Metric metric) { diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 40e763111..4bdd5ae8e 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -29,6 +29,12 @@ public class MetricAssert extends AbstractAssert { super(actual, MetricAssert.class); } + /** + * Verifies metric description + * + * @param description expected description + * @return this + */ @CanIgnoreReturnValue public MetricAssert hasDescription(String description) { isNotNull(); @@ -38,6 +44,12 @@ public MetricAssert hasDescription(String description) { return this; } + /** + * Verifies metric unit + * + * @param unit expected unit + * @return this + */ @CanIgnoreReturnValue public MetricAssert hasUnit(String unit) { isNotNull(); @@ -47,6 +59,11 @@ public MetricAssert hasUnit(String unit) { return this; } + /** + * Verifies the metric to be a gauge + * + * @return this + */ @CanIgnoreReturnValue public MetricAssert isGauge() { isNotNull(); @@ -69,14 +86,21 @@ public MetricAssert hasSum(boolean monotonic) { return this; } + /** + * Verifies the metric is a counter + * + * @return this + */ @CanIgnoreReturnValue public MetricAssert isCounter() { + // counters have a monotonic sum as their value can't decrease hasSum(true); return this; } @CanIgnoreReturnValue public MetricAssert isUpDownCounter() { + // up down counters are non-monotonic as their value can increase & decrease hasSum(false); return this; } From 65ddfb30fabc443d61e6f8c257869f49e53d3421 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:19:57 +0100 Subject: [PATCH 12/53] spotless & minor things --- .../contrib/jmxscraper/assertions/Assertions.java | 4 +--- .../jmxscraper/target_systems/MetricsVerifier.java | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java index 4f02d9cb8..4a683affe 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/Assertions.java @@ -7,9 +7,7 @@ import io.opentelemetry.proto.metrics.v1.Metric; -/** - * Dedicated Assertj extension to provide convenient fluent API for metrics testing - */ +/** Dedicated Assertj extension to provide convenient fluent API for metrics testing */ public class Assertions extends org.assertj.core.api.Assertions { public static MetricAssert assertThat(Metric metric) { diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index ff6b7c5d0..3c478a153 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -143,14 +143,10 @@ public final MetricsVerifier assertUpDownCounterWithAttributes( @CanIgnoreReturnValue public MetricsVerifier assertTypedCounter( String metricName, String description, String unit, List types) { - return registerAssert( + return register( metricName, metric -> - assertThat(metric) - .hasDescription(description) - .hasUnit(unit) - .isCounter() - .hasTypedDataPoints(types)); + metric.hasDescription(description).hasUnit(unit).isCounter().hasTypedDataPoints(types)); } @CanIgnoreReturnValue From db54835126aa714ebc36d5945261899456ced12c Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:58:46 +0100 Subject: [PATCH 13/53] add new assertion for attribute entries --- .../jmxscraper/assertions/MetricAssert.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 4bdd5ae8e..2f889a253 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -12,11 +12,14 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; import org.assertj.core.api.AbstractAssert; import org.assertj.core.internal.Integers; import org.assertj.core.internal.Iterables; +import org.assertj.core.internal.Maps; import org.assertj.core.internal.Objects; public class MetricAssert extends AbstractAssert { @@ -24,6 +27,7 @@ public class MetricAssert extends AbstractAssert { private static final Objects objects = Objects.instance(); private static final Iterables iterables = Iterables.instance(); private static final Integers integers = Integers.instance(); + private static final Maps maps = Maps.instance(); MetricAssert(Metric actual) { super(actual, MetricAssert.class); @@ -172,4 +176,39 @@ private void dataPointsCommonCheck(List dataPoints) { info.description("at least one data point expected for metric '%s'", actual.getName()); iterables.assertNotEmpty(info, dataPoints); } + + /** + * Verifies that all data points have all the expected attributes + * + * @param attributes expected attributes + * @return this + */ + @SafeVarargs + @CanIgnoreReturnValue + public final MetricAssert hasDataPointsAttributes(Map.Entry... attributes) { + return checkDataPoints( + dataPoints -> { + dataPointsCommonCheck(dataPoints); + + for (NumberDataPoint dataPoint : dataPoints) { + Map attributesMap = toMap(dataPoint.getAttributesList()); + + info.description( + "missing/unexpected data points attributes for metric '%s'", actual.getName()); + containsExactly(attributesMap, attributes); + } + }); + } + + @SafeVarargs + @SuppressWarnings("varargs") // required to avoid warning + private final void containsExactly( + Map map, Map.Entry... entries) { + maps.assertContainsExactly(info, map, entries); + } + + private static Map toMap(List list) { + return list.stream() + .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); + } } From 1bdf6946169e167f72fbabd692b5a23fdb8bd82b Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:59:37 +0100 Subject: [PATCH 14/53] check for missing assertions --- .../jmxscraper/assertions/MetricAssert.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 2f889a253..671d34971 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -29,10 +29,25 @@ public class MetricAssert extends AbstractAssert { private static final Integers integers = Integers.instance(); private static final Maps maps = Maps.instance(); + private boolean descriptionChecked; + private boolean unitChecked; + private boolean typeChecked; + MetricAssert(Metric actual) { super(actual, MetricAssert.class); } + public void validateAssertions(){ + info.description("missing assertion on description for metric '%s'", actual.getName()); + objects.assertEqual(info, descriptionChecked, true); + + info.description("missing assertion on unit for metric '%s'", actual.getName()); + objects.assertEqual(info, unitChecked, true); + + info.description("missing assertion on type for metric '%s'", actual.getName()); + objects.assertEqual(info, typeChecked, true); + } + /** * Verifies metric description * @@ -45,6 +60,7 @@ public MetricAssert hasDescription(String description) { info.description("unexpected description for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getDescription(), description); + descriptionChecked = true; return this; } @@ -60,6 +76,7 @@ public MetricAssert hasUnit(String unit) { info.description("unexpected unit for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getUnit(), unit); + unitChecked = true; return this; } @@ -74,6 +91,7 @@ public MetricAssert isGauge() { info.description("gauge expected for metric '%s'", actual.getName()); objects.assertEqual(info, actual.hasGauge(), true); + typeChecked = true; return this; } @@ -99,6 +117,7 @@ public MetricAssert hasSum(boolean monotonic) { public MetricAssert isCounter() { // counters have a monotonic sum as their value can't decrease hasSum(true); + typeChecked = true; return this; } @@ -106,6 +125,7 @@ public MetricAssert isCounter() { public MetricAssert isUpDownCounter() { // up down counters are non-monotonic as their value can increase & decrease hasSum(false); + typeChecked = true; return this; } From 9f8a3945028c8968c73e96c722cfad08a2a4d06f Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:14:07 +0100 Subject: [PATCH 15/53] verify attributes are checked in strict mode --- .../contrib/jmxscraper/assertions/MetricAssert.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 671d34971..f3280eb5a 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -9,7 +9,9 @@ import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; import io.opentelemetry.proto.metrics.v1.NumberDataPoint; +import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -32,12 +34,13 @@ public class MetricAssert extends AbstractAssert { private boolean descriptionChecked; private boolean unitChecked; private boolean typeChecked; + private boolean dataPointAttributesChecked; MetricAssert(Metric actual) { super(actual, MetricAssert.class); } - public void validateAssertions(){ + public void validateAssertions() { info.description("missing assertion on description for metric '%s'", actual.getName()); objects.assertEqual(info, descriptionChecked, true); @@ -46,6 +49,9 @@ public void validateAssertions(){ info.description("missing assertion on type for metric '%s'", actual.getName()); objects.assertEqual(info, typeChecked, true); + + info.description("missing assertion on data point attributes for metric '%s", actual.getName()); + objects.assertEqual(info, dataPointAttributesChecked, true); } /** @@ -161,6 +167,8 @@ private MetricAssert checkDataPoints(Consumer> listConsume } info.description("at least one set of data points expected for metric '%s'", actual.getName()); integers.assertGreaterThan(info, count, 0); + + dataPointAttributesChecked = true; return this; } From 6fb7960dfd0debbb46cda013da4ca4172c3d5625 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:15:32 +0100 Subject: [PATCH 16/53] enhance datapoint attributes check --- .../jmxscraper/assertions/MetricAssert.java | 69 ++++++++- .../ActiveMqIntegrationTest.java | 54 +++---- .../CassandraIntegrationTest.java | 49 ++++--- .../target_systems/JvmIntegrationTest.java | 58 ++++---- .../target_systems/MetricsVerifier.java | 136 +++++++----------- 5 files changed, 196 insertions(+), 170 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index f3280eb5a..79508539d 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -218,16 +218,81 @@ public final MetricAssert hasDataPointsAttributes(Map.Entry... a dataPoints -> { dataPointsCommonCheck(dataPoints); + Map attributesMap = new HashMap<>(); + for (Map.Entry attributeEntry : attributes) { + attributesMap.put(attributeEntry.getKey(), attributeEntry.getValue()); + } for (NumberDataPoint dataPoint : dataPoints) { - Map attributesMap = toMap(dataPoint.getAttributesList()); + Map dataPointAttributes = toMap(dataPoint.getAttributesList()); + // all attributes must match info.description( "missing/unexpected data points attributes for metric '%s'", actual.getName()); - containsExactly(attributesMap, attributes); + containsExactly(dataPointAttributes, attributes); + maps.assertContainsAllEntriesOf(info, dataPointAttributes, attributesMap); + } + }); + } + + /** + * Verifies that all data points have their attributes match one of the attributes set and that + * all provided attributes sets matched at least once. + * + * @param attributeSets sets of attributes as maps + * @return this + */ + @SafeVarargs + @CanIgnoreReturnValue + @SuppressWarnings("varargs") // required to avoid warning + public final MetricAssert hasDataPointsAttributes(Map... attributeSets) { + return checkDataPoints( + dataPoints -> { + dataPointsCommonCheck(dataPoints); + + boolean[] matchedSets = new boolean[attributeSets.length]; + + // validate each datapoint attributes match exactly one of the provided attributes set + for (NumberDataPoint dataPoint : dataPoints) { + Map map = toMap(dataPoint.getAttributesList()); + + int matchCount = 0; + for (int i = 0; i < attributeSets.length; i++) { + if (mapEquals(map, attributeSets[i])) { + matchedSets[i] = true; + matchCount++; + } + } + + info.description( + "data point attributes '%s' for metric '%s' must match exactly one of the attribute sets '%s'", + map, actual.getName(), Arrays.asList(attributeSets)); + integers.assertEqual(info, matchCount, 1); + } + + // check that all attribute sets matched at least once + for (int i = 0; i < matchedSets.length; i++) { + info.description( + "no data point matched attribute set '%s' for metric '%s'", + attributeSets[i], actual.getName()); + objects.assertEqual(info, matchedSets[i], true); } }); } + /** + * map equality utility + * + * @param m1 first map + * @param m2 second map + * @return true if the maps have exactly the same keys and values + */ + private static boolean mapEquals(Map m1, Map m2) { + if (m1.size() != m2.size()) { + return false; + } + return m1.entrySet().stream().allMatch(e -> e.getValue().equals(m2.get(e.getKey()))); + } + @SafeVarargs @SuppressWarnings("varargs") // required to avoid warning private final void containsExactly( diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index 8b9ddd00f..dab16cc42 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -43,80 +43,64 @@ protected MetricsVerifier createMetricsVerifier() { "activemq.consumer.count", "The number of consumers currently reading from the broker.", "{consumer}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertUpDownCounterWithAttributes( "activemq.producer.count", "The number of producers currently attached to the broker.", "{producer}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertUpDownCounterWithAttributes( "activemq.connection.count", "The total number of current connections.", "{connection}", - attrs -> attrs.containsOnly(entry("broker", "localhost"))) + entry("broker", "localhost")) .assertGaugeWithAttributes( "activemq.memory.usage", "The percentage of configured memory used.", "%", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertGaugeWithAttributes( "activemq.disk.store_usage", "The percentage of configured disk used for persistent messages.", "%", - attrs -> attrs.containsOnly(entry("broker", "localhost"))) + entry("broker", "localhost")) .assertGaugeWithAttributes( "activemq.disk.temp_usage", "The percentage of configured disk used for non-persistent messages.", "%", - attrs -> attrs.containsOnly(entry("broker", "localhost"))) + entry("broker", "localhost")) .assertUpDownCounterWithAttributes( "activemq.message.current", "The current number of messages waiting to be consumed.", "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertCounterWithAttributes( "activemq.message.expired", "The total number of messages not delivered because they expired.", "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertCounterWithAttributes( "activemq.message.enqueued", "The total number of messages received by the broker.", "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertCounterWithAttributes( "activemq.message.dequeued", "The total number of messages delivered to consumers.", "{message}", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")) .assertGaugeWithAttributes( "activemq.message.wait_time.avg", "The average time a message was held on a destination.", "ms", - attrs -> - attrs.containsOnly( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))); + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost")); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java index 76b206406..6562ecc78 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java @@ -5,15 +5,11 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static org.assertj.core.api.Assertions.entry; - import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import java.nio.file.Path; import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.function.Consumer; -import org.assertj.core.api.MapAssert; +import java.util.HashMap; +import java.util.Map; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -101,31 +97,34 @@ protected MetricsVerifier createMetricsVerifier() { "cassandra.client.request.count", "Number of requests by operation", "1", - attrs -> attrs.containsOnly(entry("operation", "RangeSlice")), - attrs -> attrs.containsOnly(entry("operation", "Read")), - attrs -> attrs.containsOnly(entry("operation", "Write"))) + requestCountAttributes("RangeSlice"), + requestCountAttributes("Read"), + requestCountAttributes("Write")) .assertCounterWithAttributes( "cassandra.client.request.error.count", "Number of request errors by operation", "1", - getRequestErrorCountAttributes()); + errorCountAttributes("RangeSlice", "Timeout"), + errorCountAttributes("RangeSlice", "Failure"), + errorCountAttributes("RangeSlice", "Unavailable"), + errorCountAttributes("Read", "Timeout"), + errorCountAttributes("Read", "Failure"), + errorCountAttributes("Read", "Unavailable"), + errorCountAttributes("Write", "Timeout"), + errorCountAttributes("Write", "Failure"), + errorCountAttributes("Write", "Unavailable")); } - @SuppressWarnings("unchecked") - private static Consumer>[] getRequestErrorCountAttributes() { - List operations = Arrays.asList("RangeSlice", "Read", "Write"); - List statuses = Arrays.asList("Timeout", "Failure", "Unavailable"); + private static Map errorCountAttributes(String operation, String status) { + Map map = new HashMap<>(); + map.put("operation", operation); + map.put("status", status); + return map; + } - return operations.stream() - .flatMap( - op -> - statuses.stream() - .map( - st -> - (Consumer>) - attrs -> - attrs.containsOnly( - entry("operation", op), entry("status", st)))) - .toArray(Consumer[]::new); + private static Map requestCountAttributes(String operation) { + Map map = new HashMap<>(); + map.put("operation", operation); + return map; } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index 3acbbf82c..0d897bdb3 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -44,30 +44,38 @@ protected MetricsVerifier createMetricsVerifier() { "PS Survivor Space"); List gcCollectionLabels = Arrays.asList("PS MarkSweep", "PS Scavenge"); - return MetricsVerifier.create() - .assertGauge("jvm.classes.loaded", "number of loaded classes", "1") - .assertTypedCounter( - "jvm.gc.collections.count", - "total number of collections that have occurred", - "1", - gcCollectionLabels) - .assertTypedCounter( - "jvm.gc.collections.elapsed", - "the approximate accumulated collection elapsed time in milliseconds", - "ms", - gcCollectionLabels) - .assertGauge("jvm.memory.heap.committed", "current heap usage", "by") - .assertGauge("jvm.memory.heap.init", "current heap usage", "by") - .assertGauge("jvm.memory.heap.max", "current heap usage", "by") - .assertGauge("jvm.memory.heap.used", "current heap usage", "by") - .assertGauge("jvm.memory.nonheap.committed", "current non-heap usage", "by") - .assertGauge("jvm.memory.nonheap.init", "current non-heap usage", "by") - .assertGauge("jvm.memory.nonheap.max", "current non-heap usage", "by") - .assertGauge("jvm.memory.nonheap.used", "current non-heap usage", "by") - .assertTypedGauge("jvm.memory.pool.committed", "current memory pool usage", "by", gcLabels) - .assertTypedGauge("jvm.memory.pool.init", "current memory pool usage", "by", gcLabels) - .assertTypedGauge("jvm.memory.pool.max", "current memory pool usage", "by", gcLabels) - .assertTypedGauge("jvm.memory.pool.used", "current memory pool usage", "by", gcLabels) - .assertGauge("jvm.threads.count", "number of threads", "1"); + MetricsVerifier metricsVerifier = + MetricsVerifier.create() + .assertGauge("jvm.classes.loaded", "number of loaded classes", "1") + .assertTypedCounter( + "jvm.gc.collections.count", + "total number of collections that have occurred", + "1", + gcCollectionLabels) + .register( + "jvm.gc.collections.elapsed", + metric -> + metric + .hasDescription( + "the approximate accumulated collection elapsed time in milliseconds") + .hasUnit("ms") + .isCounter() + .hasTypedDataPoints(gcCollectionLabels)) + .assertGauge("jvm.memory.heap.committed", "current heap usage", "by") + .assertGauge("jvm.memory.heap.init", "current heap usage", "by") + .assertGauge("jvm.memory.heap.max", "current heap usage", "by") + .assertGauge("jvm.memory.heap.used", "current heap usage", "by") + .assertGauge("jvm.memory.nonheap.committed", "current non-heap usage", "by") + .assertGauge("jvm.memory.nonheap.init", "current non-heap usage", "by") + .assertGauge("jvm.memory.nonheap.max", "current non-heap usage", "by") + .assertGauge("jvm.memory.nonheap.used", "current non-heap usage", "by") + .assertTypedGauge( + "jvm.memory.pool.committed", "current memory pool usage", "by", gcLabels) + .assertTypedGauge("jvm.memory.pool.init", "current memory pool usage", "by", gcLabels) + .assertTypedGauge("jvm.memory.pool.max", "current memory pool usage", "by", gcLabels) + .assertTypedGauge("jvm.memory.pool.used", "current memory pool usage", "by", gcLabels) + .assertGauge("jvm.threads.count", "number of threads", "1"); + + return metricsVerifier; } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 3c478a153..e421c9ef2 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -10,10 +10,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.contrib.jmxscraper.assertions.MetricAssert; -import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; -import io.opentelemetry.proto.metrics.v1.NumberDataPoint; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -21,11 +18,8 @@ import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; -import org.assertj.core.api.MapAssert; public class MetricsVerifier { - private static final String METRIC_VERIFICATION_FAILURE_MESSAGE = - "Verification of %s metric failed"; private final Map> assertions = new HashMap<>(); private boolean strictMode = true; @@ -38,27 +32,29 @@ private MetricsVerifier() {} * allowingExtraMetrics() method. * * @return new instance of MetricsVerifier - * @see #allowExtraMetrics() + * @see #disableStrictMode() */ public static MetricsVerifier create() { return new MetricsVerifier(); } @CanIgnoreReturnValue - public MetricsVerifier allowExtraMetrics() { + public MetricsVerifier disableStrictMode() { strictMode = false; return this; } - @CanIgnoreReturnValue - private MetricsVerifier registerAssert(String metricName, Consumer assertion) { - assertions.put(metricName, assertion); - return this; - } - @CanIgnoreReturnValue public MetricsVerifier register(String metricName, Consumer assertion) { - assertions.put(metricName, metric -> assertion.accept(assertThat(metric))); + assertions.put( + metricName, + metric -> { + MetricAssert metricAssert = assertThat(metric); + assertion.accept(metricAssert); + if (strictMode) { + metricAssert.validateAssertions(); + } + }); return this; } @@ -103,41 +99,58 @@ public MetricsVerifier assertUpDownCounter(String metricName, String description @SafeVarargs @CanIgnoreReturnValue - public final MetricsVerifier assertGaugeWithAttributes( - String metricName, - String description, - String unit, - Consumer>... attributeGroupAssertions) { - return registerAssert( + public final MetricsVerifier assertGaugeWithAttributes( // only used in activemq + String metricName, String description, String unit, Map.Entry... attributes) { + return register( metricName, - metric -> { - assertThat(metric).hasDescription(description).hasUnit(unit).isGauge(); + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isGauge() + .hasDataPointsAttributes(attributes)); + } - assertAttributedPoints( - metricName, metric.getGauge().getDataPointsList(), attributeGroupAssertions); - }); + @SafeVarargs + @CanIgnoreReturnValue + public final MetricsVerifier assertCounterWithAttributes( // TODO: used for cassandra + String metricName, String description, String unit, Map... attributeSets) { + return register( + metricName, + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isCounter() + .hasDataPointsAttributes(attributeSets)); } @SafeVarargs @CanIgnoreReturnValue public final MetricsVerifier assertCounterWithAttributes( - String metricName, - String description, - String unit, - Consumer>... attributeGroupAssertions) { - return assertSumWithAttributes( - metricName, description, unit, /* isMonotonic= */ true, attributeGroupAssertions); + String metricName, String description, String unit, Map.Entry... attributes) { + return register( + metricName, + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isCounter() + .hasDataPointsAttributes(attributes)); } @SafeVarargs @CanIgnoreReturnValue public final MetricsVerifier assertUpDownCounterWithAttributes( - String metricName, - String description, - String unit, - Consumer>... attributeGroupAssertions) { - return assertSumWithAttributes( - metricName, description, unit, /* isMonotonic= */ false, attributeGroupAssertions); + String metricName, String description, String unit, Map.Entry... attributes) { + return register( + metricName, + metric -> + metric + .hasDescription(description) + .hasUnit(unit) + .isUpDownCounter() + .hasDataPointsAttributes(attributes)); } @CanIgnoreReturnValue @@ -152,14 +165,10 @@ public MetricsVerifier assertTypedCounter( @CanIgnoreReturnValue public MetricsVerifier assertTypedGauge( String metricName, String description, String unit, List types) { - return registerAssert( + return register( metricName, metric -> - assertThat(metric) - .hasDescription(description) - .hasUnit(unit) - .isGauge() - .hasTypedDataPoints(types)); + metric.hasDescription(description).hasUnit(unit).isGauge().hasTypedDataPoints(types)); } public void verify(List metrics) { @@ -194,43 +203,4 @@ private void verifyAllExpectedMetricsWereReceived(List metrics) { fail("Metrics expected but not received: " + assertionNames); } } - - @SafeVarargs - @SuppressWarnings("CanIgnoreReturnValueSuggester") - private final MetricsVerifier assertSumWithAttributes( - String metricName, - String description, - String unit, - boolean isMonotonic, - Consumer>... attributeGroupAssertions) { - return registerAssert( - metricName, - metric -> { - assertThat(metric).hasDescription(description).hasUnit(unit).hasSum(isMonotonic); - - assertAttributedPoints( - metricName, metric.getSum().getDataPointsList(), attributeGroupAssertions); - }); - } - - @SuppressWarnings("unchecked") - private static void assertAttributedPoints( - String metricName, - List points, - Consumer>... attributeGroupAssertions) { - Consumer>[] assertions = - Arrays.stream(attributeGroupAssertions) - .map(assertion -> (Consumer>) m -> assertion.accept(assertThat(m))) - .toArray(Consumer[]::new); - - assertThat(points) - .describedAs(METRIC_VERIFICATION_FAILURE_MESSAGE, metricName) - .extracting( - numberDataPoint -> - numberDataPoint.getAttributesList().stream() - .collect( - Collectors.toMap( - KeyValue::getKey, keyValue -> keyValue.getValue().getStringValue()))) - .satisfiesExactlyInAnyOrder(assertions); - } } From a458c1c85c9ec4cf22e2a982870f9d3f76e3990d Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:37:08 +0100 Subject: [PATCH 17/53] comments, cleanup and inline a bit --- .../jmxscraper/assertions/MetricAssert.java | 3 ++- .../target_systems/ActiveMqIntegrationTest.java | 14 +++++++++----- .../jmxscraper/target_systems/MetricsVerifier.java | 8 +++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 79508539d..324f1f7c2 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -102,7 +102,7 @@ public MetricAssert isGauge() { } @CanIgnoreReturnValue - public MetricAssert hasSum(boolean monotonic) { + private MetricAssert hasSum(boolean monotonic) { isNotNull(); info.description("sum expected for metric '%s'", actual.getName()); @@ -174,6 +174,7 @@ private MetricAssert checkDataPoints(Consumer> listConsume @CanIgnoreReturnValue public MetricAssert hasTypedDataPoints(Collection types) { + // TODO: we could replace this with 'hasDataPointsAttributes' return checkDataPoints( dataPoints -> { dataPointsCommonCheck(dataPoints); diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index dab16cc42..f659a0940 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -39,12 +39,16 @@ protected JmxScraperContainer customizeScraperContainer( @Override protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() - .assertUpDownCounterWithAttributes( + .register( "activemq.consumer.count", - "The number of consumers currently reading from the broker.", - "{consumer}", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) + metric -> + metric + .hasDescription("The number of consumers currently reading from the broker.") + .hasUnit("{consumer}") + .isUpDownCounter() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) .assertUpDownCounterWithAttributes( "activemq.producer.count", "The number of producers currently attached to the broker.", diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index e421c9ef2..0e236b738 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -97,6 +97,7 @@ public MetricsVerifier assertUpDownCounter(String metricName, String description .hasDataPointsWithoutAttributes()); } + // TODO: can now be inlined @SafeVarargs @CanIgnoreReturnValue public final MetricsVerifier assertGaugeWithAttributes( // only used in activemq @@ -111,9 +112,10 @@ public final MetricsVerifier assertGaugeWithAttributes( // only used in activemq .hasDataPointsAttributes(attributes)); } + // TODO: can now be inlined @SafeVarargs @CanIgnoreReturnValue - public final MetricsVerifier assertCounterWithAttributes( // TODO: used for cassandra + public final MetricsVerifier assertCounterWithAttributes( String metricName, String description, String unit, Map... attributeSets) { return register( metricName, @@ -125,6 +127,7 @@ public final MetricsVerifier assertCounterWithAttributes( // TODO: used for cass .hasDataPointsAttributes(attributeSets)); } + // TODO: can now be inlined @SafeVarargs @CanIgnoreReturnValue public final MetricsVerifier assertCounterWithAttributes( @@ -139,6 +142,7 @@ public final MetricsVerifier assertCounterWithAttributes( .hasDataPointsAttributes(attributes)); } + // TODO: can now be inlined @SafeVarargs @CanIgnoreReturnValue public final MetricsVerifier assertUpDownCounterWithAttributes( @@ -153,6 +157,7 @@ public final MetricsVerifier assertUpDownCounterWithAttributes( .hasDataPointsAttributes(attributes)); } + // TODO: can now be inlined @CanIgnoreReturnValue public MetricsVerifier assertTypedCounter( String metricName, String description, String unit, List types) { @@ -162,6 +167,7 @@ public MetricsVerifier assertTypedCounter( metric.hasDescription(description).hasUnit(unit).isCounter().hasTypedDataPoints(types)); } + // TODO: can be inlined @CanIgnoreReturnValue public MetricsVerifier assertTypedGauge( String metricName, String description, String unit, List types) { From b9f054c963b7b73dd40f710f64ee5063484f4aa2 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:00:47 +0100 Subject: [PATCH 18/53] strict check avoids duplicate assertions --- .../jmxscraper/assertions/MetricAssert.java | 36 +++++++++++++------ .../target_systems/MetricsVerifier.java | 5 ++- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 324f1f7c2..cb9ae6475 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -31,6 +31,8 @@ public class MetricAssert extends AbstractAssert { private static final Integers integers = Integers.instance(); private static final Maps maps = Maps.instance(); + private boolean strict; + private boolean descriptionChecked; private boolean unitChecked; private boolean typeChecked; @@ -40,20 +42,26 @@ public class MetricAssert extends AbstractAssert { super(actual, MetricAssert.class); } - public void validateAssertions() { - info.description("missing assertion on description for metric '%s'", actual.getName()); - objects.assertEqual(info, descriptionChecked, true); - - info.description("missing assertion on unit for metric '%s'", actual.getName()); - objects.assertEqual(info, unitChecked, true); - - info.description("missing assertion on type for metric '%s'", actual.getName()); - objects.assertEqual(info, typeChecked, true); + public void setStrict(boolean strict) { + this.strict = strict; + } - info.description("missing assertion on data point attributes for metric '%s", actual.getName()); - objects.assertEqual(info, dataPointAttributesChecked, true); + public void strictCheck() { + strictCheck("description", true, descriptionChecked); + strictCheck("unit", true, unitChecked); + strictCheck("type", true, typeChecked); + strictCheck("data point attributes", true, dataPointAttributesChecked); } + private void strictCheck(String attribute, boolean expectedValue, boolean value) { + if(!strict) { + return; + } + String failMsgPrefix = expectedValue ? "duplicate" : "missing"; + info.description("%s assertion on %s for metric '%s'", failMsgPrefix, attribute, + actual.getName()); + objects.assertEqual(info, value, expectedValue); + } /** * Verifies metric description * @@ -66,6 +74,7 @@ public MetricAssert hasDescription(String description) { info.description("unexpected description for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getDescription(), description); + strictCheck("description", false, descriptionChecked); descriptionChecked = true; return this; } @@ -82,6 +91,7 @@ public MetricAssert hasUnit(String unit) { info.description("unexpected unit for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getUnit(), unit); + strictCheck("unit", false, unitChecked); unitChecked = true; return this; } @@ -97,6 +107,7 @@ public MetricAssert isGauge() { info.description("gauge expected for metric '%s'", actual.getName()); objects.assertEqual(info, actual.hasGauge(), true); + strictCheck("type", false, typeChecked); typeChecked = true; return this; } @@ -123,6 +134,7 @@ private MetricAssert hasSum(boolean monotonic) { public MetricAssert isCounter() { // counters have a monotonic sum as their value can't decrease hasSum(true); + strictCheck("type", false, typeChecked); typeChecked = true; return this; } @@ -131,6 +143,7 @@ public MetricAssert isCounter() { public MetricAssert isUpDownCounter() { // up down counters are non-monotonic as their value can increase & decrease hasSum(false); + strictCheck("type", false, typeChecked); typeChecked = true; return this; } @@ -168,6 +181,7 @@ private MetricAssert checkDataPoints(Consumer> listConsume info.description("at least one set of data points expected for metric '%s'", actual.getName()); integers.assertGreaterThan(info, count, 0); + strictCheck("data point attributes", false, dataPointAttributesChecked); dataPointAttributesChecked = true; return this; } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 0e236b738..95cc197f5 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -50,10 +50,9 @@ public MetricsVerifier register(String metricName, Consumer assert metricName, metric -> { MetricAssert metricAssert = assertThat(metric); + metricAssert.setStrict(strictMode); assertion.accept(metricAssert); - if (strictMode) { - metricAssert.validateAssertions(); - } + metricAssert.strictCheck(); }); return this; } From cf72d19c6050aac0eddfaa68baa93f3f32fc45af Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:02:22 +0100 Subject: [PATCH 19/53] remove obsolete comments in activemq yaml --- jmx-scraper/src/main/resources/activemq.yaml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/jmx-scraper/src/main/resources/activemq.yaml b/jmx-scraper/src/main/resources/activemq.yaml index dea6c3928..3a3ec47e5 100644 --- a/jmx-scraper/src/main/resources/activemq.yaml +++ b/jmx-scraper/src/main/resources/activemq.yaml @@ -10,15 +10,11 @@ rules: mapping: ProducerCount: metric: producer.count - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{producer}" type: updowncounter desc: The number of producers currently attached to the broker. ConsumerCount: metric: consumer.count - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{consumer}" type: updowncounter desc: The number of consumers currently reading from the broker. @@ -29,29 +25,21 @@ rules: desc: The percentage of configured memory used. QueueSize: metric: message.current - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{message}" type: updowncounter desc: The current number of messages waiting to be consumed. ExpiredCount: metric: message.expired - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{message}" type: counter desc: The total number of messages not delivered because they expired. EnqueueCount: metric: message.enqueued - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{message}" type: counter desc: The total number of messages received by the broker. DequeueCount: metric: message.dequeued - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{message}" type: counter desc: The total number of messages delivered to consumers. @@ -73,8 +61,6 @@ rules: CurrentConnectionsCount: metric: connection.count type: updowncounter - # Unit name inherited from activemq.groovy file. - # Will be updated to {} semconv notation when we switch to use original files from JMX Insights unit: "{connection}" desc: The total number of current connections. StorePercentUsage: From eab7c6914b0104a7ac9d7cde70e3ae5f2b5eb415 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:03:31 +0100 Subject: [PATCH 20/53] register -> add --- .../ActiveMqIntegrationTest.java | 2 +- .../target_systems/JvmIntegrationTest.java | 2 +- .../target_systems/MetricsVerifier.java | 20 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index f659a0940..da3e03370 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -39,7 +39,7 @@ protected JmxScraperContainer customizeScraperContainer( @Override protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() - .register( + .add( "activemq.consumer.count", metric -> metric diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index 0d897bdb3..4cb500b80 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -52,7 +52,7 @@ protected MetricsVerifier createMetricsVerifier() { "total number of collections that have occurred", "1", gcCollectionLabels) - .register( + .add( "jvm.gc.collections.elapsed", metric -> metric diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 95cc197f5..ab5b6d03f 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -45,7 +45,7 @@ public MetricsVerifier disableStrictMode() { } @CanIgnoreReturnValue - public MetricsVerifier register(String metricName, Consumer assertion) { + public MetricsVerifier add(String metricName, Consumer assertion) { assertions.put( metricName, metric -> { @@ -60,7 +60,7 @@ public MetricsVerifier register(String metricName, Consumer assert // TODO: can now be inlined @CanIgnoreReturnValue public MetricsVerifier assertGauge(String metricName, String description, String unit) { - return register( + return add( metricName, metric -> metric @@ -73,7 +73,7 @@ public MetricsVerifier assertGauge(String metricName, String description, String // TODO: can now be inlined @CanIgnoreReturnValue public MetricsVerifier assertCounter(String metricName, String description, String unit) { - return register( + return add( metricName, metric -> metric @@ -86,7 +86,7 @@ public MetricsVerifier assertCounter(String metricName, String description, Stri // TODO: can now be inlined @CanIgnoreReturnValue public MetricsVerifier assertUpDownCounter(String metricName, String description, String unit) { - return register( + return add( metricName, metric -> metric @@ -101,7 +101,7 @@ public MetricsVerifier assertUpDownCounter(String metricName, String description @CanIgnoreReturnValue public final MetricsVerifier assertGaugeWithAttributes( // only used in activemq String metricName, String description, String unit, Map.Entry... attributes) { - return register( + return add( metricName, metric -> metric @@ -116,7 +116,7 @@ public final MetricsVerifier assertGaugeWithAttributes( // only used in activemq @CanIgnoreReturnValue public final MetricsVerifier assertCounterWithAttributes( String metricName, String description, String unit, Map... attributeSets) { - return register( + return add( metricName, metric -> metric @@ -131,7 +131,7 @@ public final MetricsVerifier assertCounterWithAttributes( @CanIgnoreReturnValue public final MetricsVerifier assertCounterWithAttributes( String metricName, String description, String unit, Map.Entry... attributes) { - return register( + return add( metricName, metric -> metric @@ -146,7 +146,7 @@ public final MetricsVerifier assertCounterWithAttributes( @CanIgnoreReturnValue public final MetricsVerifier assertUpDownCounterWithAttributes( String metricName, String description, String unit, Map.Entry... attributes) { - return register( + return add( metricName, metric -> metric @@ -160,7 +160,7 @@ public final MetricsVerifier assertUpDownCounterWithAttributes( @CanIgnoreReturnValue public MetricsVerifier assertTypedCounter( String metricName, String description, String unit, List types) { - return register( + return add( metricName, metric -> metric.hasDescription(description).hasUnit(unit).isCounter().hasTypedDataPoints(types)); @@ -170,7 +170,7 @@ public MetricsVerifier assertTypedCounter( @CanIgnoreReturnValue public MetricsVerifier assertTypedGauge( String metricName, String description, String unit, List types) { - return register( + return add( metricName, metric -> metric.hasDescription(description).hasUnit(unit).isGauge().hasTypedDataPoints(types)); From 9c3390cd93ac334e9c7fa5f3e41a88ce55b848a2 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:18:34 +0100 Subject: [PATCH 21/53] reformat --- .../contrib/jmxscraper/assertions/MetricAssert.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index cb9ae6475..ca05a1cf1 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -54,14 +54,15 @@ public void strictCheck() { } private void strictCheck(String attribute, boolean expectedValue, boolean value) { - if(!strict) { + if (!strict) { return; } String failMsgPrefix = expectedValue ? "duplicate" : "missing"; - info.description("%s assertion on %s for metric '%s'", failMsgPrefix, attribute, - actual.getName()); + info.description( + "%s assertion on %s for metric '%s'", failMsgPrefix, attribute, actual.getName()); objects.assertEqual(info, value, expectedValue); } + /** * Verifies metric description * From 939278017b6de7f7fc4a34a403dc94b07124ab1e Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:18:55 +0100 Subject: [PATCH 22/53] refactor cassandra --- .../CassandraIntegrationTest.java | 184 ++++++++++++------ 1 file changed, 125 insertions(+), 59 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java index 6562ecc78..a16b4a6a0 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java @@ -39,80 +39,146 @@ protected JmxScraperContainer customizeScraperContainer( @Override protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() - .assertGauge( + .add( "cassandra.client.request.range_slice.latency.50p", - "Token range read request latency - 50th percentile", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Token range read request latency - 50th percentile") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.range_slice.latency.99p", - "Token range read request latency - 99th percentile", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Token range read request latency - 99th percentile") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.range_slice.latency.max", - "Maximum token range read request latency", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Maximum token range read request latency") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.read.latency.50p", - "Standard read request latency - 50th percentile", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Standard read request latency - 50th percentile") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.read.latency.99p", - "Standard read request latency - 99th percentile", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Standard read request latency - 99th percentile") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.read.latency.max", - "Maximum standard read request latency", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Maximum standard read request latency") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.write.latency.50p", - "Regular write request latency - 50th percentile", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Regular write request latency - 50th percentile") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.write.latency.99p", - "Regular write request latency - 99th percentile", - "us") - .assertGauge( + metric -> + metric + .hasDescription("Regular write request latency - 99th percentile") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.write.latency.max", - "Maximum regular write request latency", - "us") - .assertCounter( + metric -> + metric + .hasDescription("Maximum regular write request latency") + .hasUnit("us") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.compaction.tasks.completed", - "Number of completed compactions since server [re]start", - "1") - .assertGauge( + metric -> + metric + .hasDescription("Number of completed compactions since server [re]start") + .hasUnit("1") + .isCounter() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.compaction.tasks.pending", - "Estimated number of compactions remaining to perform", - "1") - .assertUpDownCounter( - "cassandra.storage.load.count", "Size of the on disk data size this node manages", "by") - .assertCounter( + metric -> + metric + .hasDescription("Estimated number of compactions remaining to perform") + .hasUnit("1") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "cassandra.storage.load.count", + metric -> + metric + .hasDescription("Size of the on disk data size this node manages") + .hasUnit("by") + .isUpDownCounter() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.storage.total_hints.count", - "Number of hint messages written to this node since [re]start", - "1") - .assertUpDownCounter( + metric -> + metric + .hasDescription("Number of hint messages written to this node since [re]start") + .hasUnit("1") + .isCounter() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.storage.total_hints.in_progress.count", - "Number of hints attempting to be sent currently", - "1") - .assertCounterWithAttributes( + metric -> + metric + .hasDescription("Number of hints attempting to be sent currently") + .hasUnit("1") + .isUpDownCounter() + .hasDataPointsWithoutAttributes()) + .add( "cassandra.client.request.count", - "Number of requests by operation", - "1", - requestCountAttributes("RangeSlice"), - requestCountAttributes("Read"), - requestCountAttributes("Write")) - .assertCounterWithAttributes( + metric -> + metric + .hasDescription("Number of requests by operation") + .hasUnit("1") + .isCounter() + .hasDataPointsAttributes( + requestCountAttributes("RangeSlice"), + requestCountAttributes("Read"), + requestCountAttributes("Write"))) + .add( "cassandra.client.request.error.count", - "Number of request errors by operation", - "1", - errorCountAttributes("RangeSlice", "Timeout"), - errorCountAttributes("RangeSlice", "Failure"), - errorCountAttributes("RangeSlice", "Unavailable"), - errorCountAttributes("Read", "Timeout"), - errorCountAttributes("Read", "Failure"), - errorCountAttributes("Read", "Unavailable"), - errorCountAttributes("Write", "Timeout"), - errorCountAttributes("Write", "Failure"), - errorCountAttributes("Write", "Unavailable")); + metric -> + metric + .hasDescription("Number of request errors by operation") + .hasUnit("1") + .isCounter() + .hasDataPointsAttributes( + errorCountAttributes("RangeSlice", "Timeout"), + errorCountAttributes("RangeSlice", "Failure"), + errorCountAttributes("RangeSlice", "Unavailable"), + errorCountAttributes("Read", "Timeout"), + errorCountAttributes("Read", "Failure"), + errorCountAttributes("Read", "Unavailable"), + errorCountAttributes("Write", "Timeout"), + errorCountAttributes("Write", "Failure"), + errorCountAttributes("Write", "Unavailable"))); } private static Map errorCountAttributes(String operation, String status) { From 5ae735dc099673385baa510fffeddf7ebc2f0c77 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:25:25 +0100 Subject: [PATCH 23/53] fix lint --- .../jmxscraper/assertions/MetricAssert.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index ca05a1cf1..4ea4d3de1 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -47,10 +47,10 @@ public void setStrict(boolean strict) { } public void strictCheck() { - strictCheck("description", true, descriptionChecked); - strictCheck("unit", true, unitChecked); - strictCheck("type", true, typeChecked); - strictCheck("data point attributes", true, dataPointAttributesChecked); + strictCheck("description", /* expectedValue= */ true, descriptionChecked); + strictCheck("unit", /* expectedValue= */ true, unitChecked); + strictCheck("type", /* expectedValue= */ true, typeChecked); + strictCheck("data point attributes", /* expectedValue= */ true, dataPointAttributesChecked); } private void strictCheck(String attribute, boolean expectedValue, boolean value) { @@ -75,7 +75,7 @@ public MetricAssert hasDescription(String description) { info.description("unexpected description for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getDescription(), description); - strictCheck("description", false, descriptionChecked); + strictCheck("description", /* expectedValue= */false, descriptionChecked); descriptionChecked = true; return this; } @@ -92,7 +92,7 @@ public MetricAssert hasUnit(String unit) { info.description("unexpected unit for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getUnit(), unit); - strictCheck("unit", false, unitChecked); + strictCheck("unit", /* expectedValue= */false, unitChecked); unitChecked = true; return this; } @@ -108,7 +108,7 @@ public MetricAssert isGauge() { info.description("gauge expected for metric '%s'", actual.getName()); objects.assertEqual(info, actual.hasGauge(), true); - strictCheck("type", false, typeChecked); + strictCheck("type", /* expectedValue= */false, typeChecked); typeChecked = true; return this; } @@ -135,7 +135,7 @@ private MetricAssert hasSum(boolean monotonic) { public MetricAssert isCounter() { // counters have a monotonic sum as their value can't decrease hasSum(true); - strictCheck("type", false, typeChecked); + strictCheck("type", /* expectedValue= */false, typeChecked); typeChecked = true; return this; } @@ -144,7 +144,7 @@ public MetricAssert isCounter() { public MetricAssert isUpDownCounter() { // up down counters are non-monotonic as their value can increase & decrease hasSum(false); - strictCheck("type", false, typeChecked); + strictCheck("type", /* expectedValue= */false, typeChecked); typeChecked = true; return this; } @@ -182,7 +182,7 @@ private MetricAssert checkDataPoints(Consumer> listConsume info.description("at least one set of data points expected for metric '%s'", actual.getName()); integers.assertGreaterThan(info, count, 0); - strictCheck("data point attributes", false, dataPointAttributesChecked); + strictCheck("data point attributes", /* expectedValue= */false, dataPointAttributesChecked); dataPointAttributesChecked = true; return this; } From 2c65318507349e95e40f29006cafede1282665fa Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:25:34 +0100 Subject: [PATCH 24/53] refactor activemq --- .../ActiveMqIntegrationTest.java | 134 ++++++++++++------ 1 file changed, 87 insertions(+), 47 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index da3e03370..a5c5522bf 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -49,62 +49,102 @@ protected MetricsVerifier createMetricsVerifier() { .hasDataPointsAttributes( entry("destination", "ActiveMQ.Advisory.MasterBroker"), entry("broker", "localhost"))) - .assertUpDownCounterWithAttributes( + .add( "activemq.producer.count", - "The number of producers currently attached to the broker.", - "{producer}", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) - .assertUpDownCounterWithAttributes( + metric -> + metric + .hasDescription("The number of producers currently attached to the broker.") + .hasUnit("{producer}") + .isUpDownCounter() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .add( "activemq.connection.count", - "The total number of current connections.", - "{connection}", - entry("broker", "localhost")) - .assertGaugeWithAttributes( + metric -> + metric + .hasDescription("The total number of current connections.") + .hasUnit("{connection}") + .isUpDownCounter() + .hasDataPointsAttributes(entry("broker", "localhost"))) + .add( "activemq.memory.usage", - "The percentage of configured memory used.", - "%", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) - .assertGaugeWithAttributes( + metric -> + metric + .hasDescription("The percentage of configured memory used.") + .hasUnit("%") + .isGauge() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .add( "activemq.disk.store_usage", - "The percentage of configured disk used for persistent messages.", - "%", - entry("broker", "localhost")) - .assertGaugeWithAttributes( + metric -> + metric + .hasDescription( + "The percentage of configured disk used for persistent messages.") + .hasUnit("%") + .isGauge() + .hasDataPointsAttributes(entry("broker", "localhost"))) + .add( "activemq.disk.temp_usage", - "The percentage of configured disk used for non-persistent messages.", - "%", - entry("broker", "localhost")) - .assertUpDownCounterWithAttributes( + metric -> + metric + .hasDescription( + "The percentage of configured disk used for non-persistent messages.") + .hasUnit("%") + .isGauge() + .hasDataPointsAttributes(entry("broker", "localhost"))) + .add( "activemq.message.current", - "The current number of messages waiting to be consumed.", - "{message}", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) - .assertCounterWithAttributes( + metric -> + metric + .hasDescription("The current number of messages waiting to be consumed.") + .hasUnit("{message}") + .isUpDownCounter() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .add( "activemq.message.expired", - "The total number of messages not delivered because they expired.", - "{message}", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) - .assertCounterWithAttributes( + metric -> + metric + .hasDescription( + "The total number of messages not delivered because they expired.") + .hasUnit("{message}") + .isCounter() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .add( "activemq.message.enqueued", - "The total number of messages received by the broker.", - "{message}", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) - .assertCounterWithAttributes( + metric -> + metric + .hasDescription("The total number of messages received by the broker.") + .hasUnit("{message}") + .isCounter() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .add( "activemq.message.dequeued", - "The total number of messages delivered to consumers.", - "{message}", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")) - .assertGaugeWithAttributes( + metric -> + metric + .hasDescription("The total number of messages delivered to consumers.") + .hasUnit("{message}") + .isCounter() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))) + .add( "activemq.message.wait_time.avg", - "The average time a message was held on a destination.", - "ms", - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost")); + metric -> + metric + .hasDescription("The average time a message was held on a destination.") + .hasUnit("ms") + .isGauge() + .hasDataPointsAttributes( + entry("destination", "ActiveMQ.Advisory.MasterBroker"), + entry("broker", "localhost"))); } } From a670561685a132168fc966a93c1e3f565d314821 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:50:04 +0100 Subject: [PATCH 25/53] refactor jvm metrics --- .../jmxscraper/assertions/MetricAssert.java | 13 +- .../target_systems/JvmIntegrationTest.java | 175 ++++++++++++++---- .../target_systems/MetricsVerifier.java | 19 +- 3 files changed, 157 insertions(+), 50 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 4ea4d3de1..d1ca9af4e 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -75,7 +75,7 @@ public MetricAssert hasDescription(String description) { info.description("unexpected description for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getDescription(), description); - strictCheck("description", /* expectedValue= */false, descriptionChecked); + strictCheck("description", /* expectedValue= */ false, descriptionChecked); descriptionChecked = true; return this; } @@ -92,7 +92,7 @@ public MetricAssert hasUnit(String unit) { info.description("unexpected unit for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getUnit(), unit); - strictCheck("unit", /* expectedValue= */false, unitChecked); + strictCheck("unit", /* expectedValue= */ false, unitChecked); unitChecked = true; return this; } @@ -108,7 +108,7 @@ public MetricAssert isGauge() { info.description("gauge expected for metric '%s'", actual.getName()); objects.assertEqual(info, actual.hasGauge(), true); - strictCheck("type", /* expectedValue= */false, typeChecked); + strictCheck("type", /* expectedValue= */ false, typeChecked); typeChecked = true; return this; } @@ -135,7 +135,7 @@ private MetricAssert hasSum(boolean monotonic) { public MetricAssert isCounter() { // counters have a monotonic sum as their value can't decrease hasSum(true); - strictCheck("type", /* expectedValue= */false, typeChecked); + strictCheck("type", /* expectedValue= */ false, typeChecked); typeChecked = true; return this; } @@ -144,7 +144,7 @@ public MetricAssert isCounter() { public MetricAssert isUpDownCounter() { // up down counters are non-monotonic as their value can increase & decrease hasSum(false); - strictCheck("type", /* expectedValue= */false, typeChecked); + strictCheck("type", /* expectedValue= */ false, typeChecked); typeChecked = true; return this; } @@ -182,14 +182,13 @@ private MetricAssert checkDataPoints(Consumer> listConsume info.description("at least one set of data points expected for metric '%s'", actual.getName()); integers.assertGreaterThan(info, count, 0); - strictCheck("data point attributes", /* expectedValue= */false, dataPointAttributesChecked); + strictCheck("data point attributes", /* expectedValue= */ false, dataPointAttributesChecked); dataPointAttributesChecked = true; return this; } @CanIgnoreReturnValue public MetricAssert hasTypedDataPoints(Collection types) { - // TODO: we could replace this with 'hasDataPointsAttributes' return checkDataPoints( dataPoints -> { dataPointsCommonCheck(dataPoints); diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index 4cb500b80..a0decc5b7 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -44,38 +44,147 @@ protected MetricsVerifier createMetricsVerifier() { "PS Survivor Space"); List gcCollectionLabels = Arrays.asList("PS MarkSweep", "PS Scavenge"); - MetricsVerifier metricsVerifier = - MetricsVerifier.create() - .assertGauge("jvm.classes.loaded", "number of loaded classes", "1") - .assertTypedCounter( - "jvm.gc.collections.count", - "total number of collections that have occurred", - "1", - gcCollectionLabels) - .add( - "jvm.gc.collections.elapsed", - metric -> - metric - .hasDescription( - "the approximate accumulated collection elapsed time in milliseconds") - .hasUnit("ms") - .isCounter() - .hasTypedDataPoints(gcCollectionLabels)) - .assertGauge("jvm.memory.heap.committed", "current heap usage", "by") - .assertGauge("jvm.memory.heap.init", "current heap usage", "by") - .assertGauge("jvm.memory.heap.max", "current heap usage", "by") - .assertGauge("jvm.memory.heap.used", "current heap usage", "by") - .assertGauge("jvm.memory.nonheap.committed", "current non-heap usage", "by") - .assertGauge("jvm.memory.nonheap.init", "current non-heap usage", "by") - .assertGauge("jvm.memory.nonheap.max", "current non-heap usage", "by") - .assertGauge("jvm.memory.nonheap.used", "current non-heap usage", "by") - .assertTypedGauge( - "jvm.memory.pool.committed", "current memory pool usage", "by", gcLabels) - .assertTypedGauge("jvm.memory.pool.init", "current memory pool usage", "by", gcLabels) - .assertTypedGauge("jvm.memory.pool.max", "current memory pool usage", "by", gcLabels) - .assertTypedGauge("jvm.memory.pool.used", "current memory pool usage", "by", gcLabels) - .assertGauge("jvm.threads.count", "number of threads", "1"); - - return metricsVerifier; + return MetricsVerifier.create() + .add( + "jvm.classes.loaded", + metric -> + metric + .hasDescription("number of loaded classes") + .hasUnit("1") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.gc.collections.count", + metric -> + metric + .hasDescription("total number of collections that have occurred") + .hasUnit("1") + .isCounter() + .hasTypedDataPoints(gcCollectionLabels)) + .add( + "jvm.gc.collections.elapsed", + metric -> + metric + .hasDescription( + "the approximate accumulated collection elapsed time in milliseconds") + .hasUnit("ms") + .isCounter() + .hasTypedDataPoints(gcCollectionLabels)) + .add( + "jvm.memory.heap.committed", + metric -> + metric + .hasDescription("current heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.heap.init", + metric -> + metric + .hasDescription("current heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.heap.max", + metric -> + metric + .hasDescription("current heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.heap.used", + metric -> + metric + .hasDescription("current heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.nonheap.committed", + metric -> + metric + .hasDescription("current non-heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.nonheap.init", + metric -> + metric + .hasDescription("current non-heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.nonheap.max", + metric -> + metric + .hasDescription("current non-heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.nonheap.used", + metric -> + metric + .hasDescription("current non-heap usage") + .hasUnit("by") + .isGauge() + .hasDataPointsWithoutAttributes()) + .add( + "jvm.memory.pool.committed", + metric -> + metric + .hasDescription("current memory pool usage") + .hasUnit("by") + .isGauge() + .hasTypedDataPoints(gcLabels)) + .add( + "jvm.memory.pool.init", + metric -> + metric + .hasDescription("current memory pool usage") + .hasUnit("by") + .isGauge() + .hasTypedDataPoints(gcLabels)) + .add( + "jvm.memory.pool.max", + metric -> + metric + .hasDescription("current memory pool usage") + .hasUnit("by") + .isGauge() + .hasTypedDataPoints(gcLabels)) + .add( + "jvm.memory.pool.used", + metric -> + metric + .hasDescription("current memory pool usage") + .hasUnit("by") + .isGauge() + .hasTypedDataPoints(gcLabels)) + .add( + "jvm.threads.count", + metric -> + metric + .hasDescription("number of threads") + .hasUnit("1") + .isGauge() + .hasDataPointsWithoutAttributes()); } + + /* + List gcLabels = + Arrays.asList( + "Code Cache", + "PS Eden Space", + "PS Old Gen", + "Metaspace", + "Compressed Class Space", + "PS Survivor Space"); + List gcCollectionLabels = Arrays.asList("PS MarkSweep", "PS Scavenge"); + */ } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index ab5b6d03f..f3cfe4825 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -70,6 +70,15 @@ public MetricsVerifier assertGauge(String metricName, String description, String .hasDataPointsWithoutAttributes()); } + @CanIgnoreReturnValue + public MetricsVerifier assertTypedGauge( + String metricName, String description, String unit, List types) { + return add( + metricName, + metric -> + metric.hasDescription(description).hasUnit(unit).isGauge().hasTypedDataPoints(types)); + } + // TODO: can now be inlined @CanIgnoreReturnValue public MetricsVerifier assertCounter(String metricName, String description, String unit) { @@ -166,16 +175,6 @@ public MetricsVerifier assertTypedCounter( metric.hasDescription(description).hasUnit(unit).isCounter().hasTypedDataPoints(types)); } - // TODO: can be inlined - @CanIgnoreReturnValue - public MetricsVerifier assertTypedGauge( - String metricName, String description, String unit, List types) { - return add( - metricName, - metric -> - metric.hasDescription(description).hasUnit(unit).isGauge().hasTypedDataPoints(types)); - } - public void verify(List metrics) { verifyAllExpectedMetricsWereReceived(metrics); From df09034d4043f9ee69c0648d7b6e4ccde897f61d Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:52:54 +0100 Subject: [PATCH 26/53] remove unused code --- .../target_systems/MetricAssertions.java | 32 ----- .../target_systems/MetricsVerifier.java | 118 ------------------ 2 files changed, 150 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java index 881ccbf07..aa2602d48 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java @@ -6,7 +6,6 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; @@ -47,24 +46,6 @@ static void assertSum( assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); } - static void assertTypedGauge( - Metric metric, String name, String description, String unit, List types) { - assertThat(metric.getName()).isEqualTo(name); - assertThat(metric.getDescription()).isEqualTo(description); - assertThat(metric.getUnit()).isEqualTo(unit); - assertThat(metric.hasGauge()).isTrue(); - assertTypedPoints(metric.getGauge().getDataPointsList(), types); - } - - static void assertTypedSum( - Metric metric, String name, String description, String unit, List types) { - assertThat(metric.getName()).isEqualTo(name); - assertThat(metric.getDescription()).isEqualTo(description); - assertThat(metric.getUnit()).isEqualTo(unit); - assertThat(metric.hasSum()).isTrue(); - assertTypedPoints(metric.getSum().getDataPointsList(), types); - } - @SafeVarargs static void assertSumWithAttributes( Metric metric, @@ -122,19 +103,6 @@ static void assertGaugeWithAttributes( assertAttributedPoints(metric.getGauge().getDataPointsList(), attributeGroupAssertions); } - @SuppressWarnings("unchecked") - private static void assertTypedPoints(List points, List types) { - Consumer>[] assertions = - types.stream() - .map( - type -> - (Consumer>) - attrs -> attrs.containsOnly(entry("name", type))) - .toArray(Consumer[]::new); - - assertAttributedPoints(points, assertions); - } - @SuppressWarnings("unchecked") private static void assertAttributedPoints( List points, diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index f3cfe4825..92ef930cc 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -57,124 +57,6 @@ public MetricsVerifier add(String metricName, Consumer assertion) return this; } - // TODO: can now be inlined - @CanIgnoreReturnValue - public MetricsVerifier assertGauge(String metricName, String description, String unit) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isGauge() - .hasDataPointsWithoutAttributes()); - } - - @CanIgnoreReturnValue - public MetricsVerifier assertTypedGauge( - String metricName, String description, String unit, List types) { - return add( - metricName, - metric -> - metric.hasDescription(description).hasUnit(unit).isGauge().hasTypedDataPoints(types)); - } - - // TODO: can now be inlined - @CanIgnoreReturnValue - public MetricsVerifier assertCounter(String metricName, String description, String unit) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isCounter() - .hasDataPointsWithoutAttributes()); - } - - // TODO: can now be inlined - @CanIgnoreReturnValue - public MetricsVerifier assertUpDownCounter(String metricName, String description, String unit) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isUpDownCounter() - .hasDataPointsWithoutAttributes()); - } - - // TODO: can now be inlined - @SafeVarargs - @CanIgnoreReturnValue - public final MetricsVerifier assertGaugeWithAttributes( // only used in activemq - String metricName, String description, String unit, Map.Entry... attributes) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isGauge() - .hasDataPointsAttributes(attributes)); - } - - // TODO: can now be inlined - @SafeVarargs - @CanIgnoreReturnValue - public final MetricsVerifier assertCounterWithAttributes( - String metricName, String description, String unit, Map... attributeSets) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isCounter() - .hasDataPointsAttributes(attributeSets)); - } - - // TODO: can now be inlined - @SafeVarargs - @CanIgnoreReturnValue - public final MetricsVerifier assertCounterWithAttributes( - String metricName, String description, String unit, Map.Entry... attributes) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isCounter() - .hasDataPointsAttributes(attributes)); - } - - // TODO: can now be inlined - @SafeVarargs - @CanIgnoreReturnValue - public final MetricsVerifier assertUpDownCounterWithAttributes( - String metricName, String description, String unit, Map.Entry... attributes) { - return add( - metricName, - metric -> - metric - .hasDescription(description) - .hasUnit(unit) - .isUpDownCounter() - .hasDataPointsAttributes(attributes)); - } - - // TODO: can now be inlined - @CanIgnoreReturnValue - public MetricsVerifier assertTypedCounter( - String metricName, String description, String unit, List types) { - return add( - metricName, - metric -> - metric.hasDescription(description).hasUnit(unit).isCounter().hasTypedDataPoints(types)); - } - public void verify(List metrics) { verifyAllExpectedMetricsWereReceived(metrics); From 06a968f7a74b2ae460c32a30a11daa39b70682b8 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:15:02 +0100 Subject: [PATCH 27/53] recycle assertions when we can --- .../target_systems/MetricAssertions.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java index aa2602d48..d5601a9c8 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java @@ -5,7 +5,7 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static org.assertj.core.api.Assertions.assertThat; +import static io.opentelemetry.contrib.jmxscraper.assertions.Assertions.assertThat; import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; @@ -24,11 +24,11 @@ private MetricAssertions() {} static void assertGauge(Metric metric, String name, String description, String unit) { assertThat(metric.getName()).isEqualTo(name); - assertThat(metric.getDescription()).isEqualTo(description); - assertThat(metric.getUnit()).isEqualTo(unit); - assertThat(metric.hasGauge()).isTrue(); - assertThat(metric.getGauge().getDataPointsList()) - .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); + assertThat(metric) + .hasDescription(description) + .hasUnit(unit) + .isGauge() + .hasDataPointsWithoutAttributes(); } static void assertSum(Metric metric, String name, String description, String unit) { @@ -38,12 +38,13 @@ static void assertSum(Metric metric, String name, String description, String uni static void assertSum( Metric metric, String name, String description, String unit, boolean isMonotonic) { assertThat(metric.getName()).isEqualTo(name); - assertThat(metric.getDescription()).isEqualTo(description); - assertThat(metric.getUnit()).isEqualTo(unit); assertThat(metric.hasSum()).isTrue(); - assertThat(metric.getSum().getDataPointsList()) - .satisfiesExactly(point -> assertThat(point.getAttributesList()).isEmpty()); assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); + + assertThat(metric) + .hasDescription(description) + .hasUnit(unit) + .hasDataPointsWithoutAttributes(); } @SafeVarargs @@ -65,9 +66,11 @@ static void assertSumWithAttributes( String unit, boolean isMonotonic, Consumer>... attributeGroupAssertions) { + assertThat(metric.getName()).isEqualTo(name); assertThat(metric.getDescription()).isEqualTo(description); assertThat(metric.getUnit()).isEqualTo(unit); + assertThat(metric.hasSum()).describedAs("sum expected").isTrue(); assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); assertAttributedPoints(metric.getSum().getDataPointsList(), attributeGroupAssertions); @@ -81,9 +84,12 @@ static void assertSumWithAttributesMultiplePoints( String unit, boolean isMonotonic, Consumer>... attributeGroupAssertions) { + assertThat(metric.getName()).isEqualTo(name); - assertThat(metric.getDescription()).isEqualTo(description); - assertThat(metric.getUnit()).isEqualTo(unit); + assertThat(metric) + .hasDescription(description) + .hasUnit(unit); + assertThat(metric.hasSum()).isTrue(); assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); assertAttributedMultiplePoints(metric.getSum().getDataPointsList(), attributeGroupAssertions); @@ -97,9 +103,12 @@ static void assertGaugeWithAttributes( String unit, Consumer>... attributeGroupAssertions) { assertThat(metric.getName()).isEqualTo(name); - assertThat(metric.getDescription()).isEqualTo(description); - assertThat(metric.getUnit()).isEqualTo(unit); - assertThat(metric.hasGauge()).isTrue(); + + assertThat(metric) + .hasDescription(description) + .hasUnit(unit) + .isGauge(); + assertAttributedPoints(metric.getGauge().getDataPointsList(), attributeGroupAssertions); } From 8062a962c5879bdd4866f0b8173950aac6d062cd Mon Sep 17 00:00:00 2001 From: robsunday Date: Thu, 28 Nov 2024 18:18:29 +0100 Subject: [PATCH 28/53] Added some JavaDocs. Minor refactorings, mostly renaming. Fixed typos. --- .../jmxscraper/assertions/MetricAssert.java | 41 +++++++++++-------- .../target_systems/MetricAssertions.java | 14 ++----- .../target_systems/MetricsVerifier.java | 29 ++++++++++++- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index d1ca9af4e..7b50011e7 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -47,20 +47,22 @@ public void setStrict(boolean strict) { } public void strictCheck() { - strictCheck("description", /* expectedValue= */ true, descriptionChecked); - strictCheck("unit", /* expectedValue= */ true, unitChecked); - strictCheck("type", /* expectedValue= */ true, typeChecked); - strictCheck("data point attributes", /* expectedValue= */ true, dataPointAttributesChecked); + strictCheck("description", /* expectedCheckStatus= */ true, descriptionChecked); + strictCheck("unit", /* expectedCheckStatus= */ true, unitChecked); + strictCheck("type", /* expectedCheckStatus= */ true, typeChecked); + strictCheck( + "data point attributes", /* expectedCheckStatus= */ true, dataPointAttributesChecked); } - private void strictCheck(String attribute, boolean expectedValue, boolean value) { + private void strictCheck( + String metricProperty, boolean expectedCheckStatus, boolean actualCheckStatus) { if (!strict) { return; } - String failMsgPrefix = expectedValue ? "duplicate" : "missing"; + String failMsgPrefix = expectedCheckStatus ? "duplicate" : "missing"; info.description( - "%s assertion on %s for metric '%s'", failMsgPrefix, attribute, actual.getName()); - objects.assertEqual(info, value, expectedValue); + "%s assertion on %s for metric '%s'", failMsgPrefix, metricProperty, actual.getName()); + objects.assertEqual(info, actualCheckStatus, expectedCheckStatus); } /** @@ -75,7 +77,7 @@ public MetricAssert hasDescription(String description) { info.description("unexpected description for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getDescription(), description); - strictCheck("description", /* expectedValue= */ false, descriptionChecked); + strictCheck("description", /* expectedCheckStatus= */ false, descriptionChecked); descriptionChecked = true; return this; } @@ -92,13 +94,13 @@ public MetricAssert hasUnit(String unit) { info.description("unexpected unit for metric '%s'", actual.getName()); objects.assertEqual(info, actual.getUnit(), unit); - strictCheck("unit", /* expectedValue= */ false, unitChecked); + strictCheck("unit", /* expectedCheckStatus= */ false, unitChecked); unitChecked = true; return this; } /** - * Verifies the metric to be a gauge + * Verifies the metric is a gauge * * @return this */ @@ -108,7 +110,7 @@ public MetricAssert isGauge() { info.description("gauge expected for metric '%s'", actual.getName()); objects.assertEqual(info, actual.hasGauge(), true); - strictCheck("type", /* expectedValue= */ false, typeChecked); + strictCheck("type", /* expectedCheckStatus= */ false, typeChecked); typeChecked = true; return this; } @@ -135,16 +137,21 @@ private MetricAssert hasSum(boolean monotonic) { public MetricAssert isCounter() { // counters have a monotonic sum as their value can't decrease hasSum(true); - strictCheck("type", /* expectedValue= */ false, typeChecked); + strictCheck("type", /* expectedCheckStatus= */ false, typeChecked); typeChecked = true; return this; } + /** + * Verifies the metric is an up-down counter + * + * @return this + */ @CanIgnoreReturnValue public MetricAssert isUpDownCounter() { // up down counters are non-monotonic as their value can increase & decrease hasSum(false); - strictCheck("type", /* expectedValue= */ false, typeChecked); + strictCheck("type", /* expectedCheckStatus= */ false, typeChecked); typeChecked = true; return this; } @@ -169,7 +176,7 @@ public MetricAssert hasDataPointsWithoutAttributes() { @CanIgnoreReturnValue private MetricAssert checkDataPoints(Consumer> listConsumer) { // in practice usually one set of data points is provided but the - // protobuf does not enforce that so we have to ensure checking at least one + // protobuf does not enforce that, so we have to ensure checking at least one int count = 0; if (actual.hasGauge()) { count++; @@ -182,7 +189,7 @@ private MetricAssert checkDataPoints(Consumer> listConsume info.description("at least one set of data points expected for metric '%s'", actual.getName()); integers.assertGreaterThan(info, count, 0); - strictCheck("data point attributes", /* expectedValue= */ false, dataPointAttributesChecked); + strictCheck("data point attributes", /* expectedCheckStatus= */ false, dataPointAttributesChecked); dataPointAttributesChecked = true; return this; } @@ -295,7 +302,7 @@ public final MetricAssert hasDataPointsAttributes(Map... attribu } /** - * map equality utility + * Map equality utility * * @param m1 first map * @param m2 second map diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java index d5601a9c8..3cc4e8d50 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java @@ -41,10 +41,7 @@ static void assertSum( assertThat(metric.hasSum()).isTrue(); assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); - assertThat(metric) - .hasDescription(description) - .hasUnit(unit) - .hasDataPointsWithoutAttributes(); + assertThat(metric).hasDescription(description).hasUnit(unit).hasDataPointsWithoutAttributes(); } @SafeVarargs @@ -86,9 +83,7 @@ static void assertSumWithAttributesMultiplePoints( Consumer>... attributeGroupAssertions) { assertThat(metric.getName()).isEqualTo(name); - assertThat(metric) - .hasDescription(description) - .hasUnit(unit); + assertThat(metric).hasDescription(description).hasUnit(unit); assertThat(metric.hasSum()).isTrue(); assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); @@ -104,10 +99,7 @@ static void assertGaugeWithAttributes( Consumer>... attributeGroupAssertions) { assertThat(metric.getName()).isEqualTo(name); - assertThat(metric) - .hasDescription(description) - .hasUnit(unit) - .isGauge(); + assertThat(metric).hasDescription(description).hasUnit(unit).isGauge(); assertAttributedPoints(metric.getGauge().getDataPointsList(), attributeGroupAssertions); } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java index 92ef930cc..5afd1f48a 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricsVerifier.java @@ -29,7 +29,7 @@ private MetricsVerifier() {} /** * Create instance of MetricsVerifier configured to fail verification if any metric was not * verified because there is no assertion defined for it. This behavior can be changed by calling - * allowingExtraMetrics() method. + * {@link #disableStrictMode()} method. * * @return new instance of MetricsVerifier * @see #disableStrictMode() @@ -38,12 +38,29 @@ public static MetricsVerifier create() { return new MetricsVerifier(); } + /** + * Disable strict checks of metric assertions. It means that all metrics checks added after + * calling this method will not enforce asserting all metric properties and will not detect + * duplicate property assertions. Also, there will be no error reported if any of metrics was + * skipped because no assertion was added for it. + * + * @return this + * @see #verify(List) + * @see #add(String, Consumer) + */ @CanIgnoreReturnValue public MetricsVerifier disableStrictMode() { strictMode = false; return this; } + /** + * Add assertion for given metric + * + * @param metricName name of metric to be verified by provided assertion + * @param assertion an assertion to verify properties of the metric + * @return this + */ @CanIgnoreReturnValue public MetricsVerifier add(String metricName, Consumer assertion) { assertions.put( @@ -57,6 +74,15 @@ public MetricsVerifier add(String metricName, Consumer assertion) return this; } + /** + * Execute all defined assertions against provided list of metrics. Error is reported if any of + * defined assertions failed. Error is also reported if any of expected metrics was not present in + * the metrics list, unless strict mode is disabled with {@link #disableStrictMode()}. + * + * @param metrics list of metrics to be verified + * @see #add(String, Consumer) + * @see #disableStrictMode() + */ public void verify(List metrics) { verifyAllExpectedMetricsWereReceived(metrics); @@ -78,7 +104,6 @@ public void verify(List metrics) { } } - @SuppressWarnings("SystemOut") private void verifyAllExpectedMetricsWereReceived(List metrics) { Set receivedMetricNames = metrics.stream().map(Metric::getName).collect(Collectors.toSet()); From 4bed658740c23a8d0a88c9c84aceb02690a440c4 Mon Sep 17 00:00:00 2001 From: robsunday Date: Fri, 29 Nov 2024 09:30:36 +0100 Subject: [PATCH 29/53] Cleanup --- .../target_systems/JvmIntegrationTest.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java index a0decc5b7..70dacdccc 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JvmIntegrationTest.java @@ -175,16 +175,4 @@ protected MetricsVerifier createMetricsVerifier() { .isGauge() .hasDataPointsWithoutAttributes()); } - - /* - List gcLabels = - Arrays.asList( - "Code Cache", - "PS Eden Space", - "PS Old Gen", - "Metaspace", - "Compressed Class Space", - "PS Survivor Space"); - List gcCollectionLabels = Arrays.asList("PS MarkSweep", "PS Scavenge"); - */ } From fddc5fc09cf61b7b21bb9aa719e7113ff695927b Mon Sep 17 00:00:00 2001 From: robsunday Date: Fri, 29 Nov 2024 09:45:24 +0100 Subject: [PATCH 30/53] Spotless fix --- .../contrib/jmxscraper/assertions/MetricAssert.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 7b50011e7..f44c57888 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -189,7 +189,8 @@ private MetricAssert checkDataPoints(Consumer> listConsume info.description("at least one set of data points expected for metric '%s'", actual.getName()); integers.assertGreaterThan(info, count, 0); - strictCheck("data point attributes", /* expectedCheckStatus= */ false, dataPointAttributesChecked); + strictCheck( + "data point attributes", /* expectedCheckStatus= */ false, dataPointAttributesChecked); dataPointAttributesChecked = true; return this; } From fd820426a8784058b69e3cc4a20088388e61ec92 Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 4 Dec 2024 10:42:07 +0100 Subject: [PATCH 31/53] Refactoring of data point attribute assertions --- .../assertions/AttributeMatcher.java | 68 ++ .../assertions/AttributeValueMatcher.java | 41 + .../assertions/DataPointAttributes.java | 30 + .../jmxscraper/assertions/MetricAssert.java | 89 +- .../ActiveMqIntegrationTest.java | 65 +- .../CassandraIntegrationTest.java | 30 +- .../target_systems/HBaseIntegrationTest.java | 894 ++++++++++-------- .../target_systems/JettyIntegrationTest.java | 108 ++- 8 files changed, 764 insertions(+), 561 deletions(-) create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java new file mode 100644 index 000000000..fdb63d3d6 --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -0,0 +1,68 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.jmxscraper.assertions; + +import static io.opentelemetry.contrib.jmxscraper.assertions.AttributeValueMatcher.ANY_VALUE_MATCHER; + +import java.util.Objects; + +/** Implements functionality of matching data point attributes. */ +public class AttributeMatcher { + private final String name; + private final AttributeValueMatcher attributeValueMatcher; + + /** + * Create instance used to match data point attribute with te same name and with any value. + * + * @param name attribute name + */ + AttributeMatcher(String name) { + this.name = name; + this.attributeValueMatcher = ANY_VALUE_MATCHER; + } + + /** + * Create instance used to match data point attribute with te same name and with the same value. + * + * @param name attribute name + * @param value attribute value + */ + AttributeMatcher(String name, String value) { + this.name = name; + this.attributeValueMatcher = new AttributeValueMatcher(value); + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AttributeMatcher)) { + return false; + } + AttributeMatcher other = (AttributeMatcher) o; + return Objects.equals(name, other.name) + && attributeValueMatcher.matchValue(other.attributeValueMatcher); + } + + @Override + public int hashCode() { + // Do not use value matcher here to support value wildcards + return Objects.hash(name); + } + + @Override + public String toString() { + return attributeValueMatcher.getValue() == null + ? '{' + name + '}' + : '{' + name + '=' + attributeValueMatcher.getValue() + '}'; + } + ; +} diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java new file mode 100644 index 000000000..6eea6cbd5 --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.jmxscraper.assertions; + +import java.util.Objects; + +class AttributeValueMatcher { + static final AttributeValueMatcher ANY_VALUE_MATCHER = new AttributeValueMatcher(); + + private final String value; + + AttributeValueMatcher() { + this(null); + } + + AttributeValueMatcher(String value) { + this.value = value; + } + + String getValue() { + return value; + } + + /** + * Match the value held by this and the other AttributeValueMatcher instances. Null value means + * "any value", that's why if any of the values is null they are considered as matching. If both + * values are not null then they must be equal. + * + * @param other the other matcher to compare value with + * @return true if values held by both matchers are matching, false otherwise. + */ + boolean matchValue(AttributeValueMatcher other) { + if ((value == null) || (other.value == null)) { + return true; + } + return Objects.equals(value, other.value); + } +} diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java new file mode 100644 index 000000000..7b0f40e1a --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.jmxscraper.assertions; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Utility class implementing convenience static methods to construct data point attribute matchers + * and sets of matchers. + */ +public class DataPointAttributes { + private DataPointAttributes() {} + + public static AttributeMatcher attribute(String name, String value) { + return new AttributeMatcher(name, value); + } + + public static AttributeMatcher attributeWithAnyValue(String name) { + return new AttributeMatcher(name); + } + + public static Set attributeSet(AttributeMatcher... attributes) { + return Arrays.stream(attributes).collect(Collectors.toSet()); + } +} diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index f44c57888..307874b78 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -5,23 +5,23 @@ package io.opentelemetry.contrib.jmxscraper.assertions; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; + import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.metrics.v1.Metric; import io.opentelemetry.proto.metrics.v1.NumberDataPoint; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; +import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; import org.assertj.core.api.AbstractAssert; import org.assertj.core.internal.Integers; import org.assertj.core.internal.Iterables; -import org.assertj.core.internal.Maps; import org.assertj.core.internal.Objects; public class MetricAssert extends AbstractAssert { @@ -29,7 +29,6 @@ public class MetricAssert extends AbstractAssert { private static final Objects objects = Objects.instance(); private static final Iterables iterables = Iterables.instance(); private static final Integers integers = Integers.instance(); - private static final Maps maps = Maps.instance(); private boolean strict; @@ -59,7 +58,7 @@ private void strictCheck( if (!strict) { return; } - String failMsgPrefix = expectedCheckStatus ? "duplicate" : "missing"; + String failMsgPrefix = expectedCheckStatus ? "Missing" : "Duplicate"; info.description( "%s assertion on %s for metric '%s'", failMsgPrefix, metricProperty, actual.getName()); objects.assertEqual(info, actualCheckStatus, expectedCheckStatus); @@ -122,8 +121,8 @@ private MetricAssert hasSum(boolean monotonic) { info.description("sum expected for metric '%s'", actual.getName()); objects.assertEqual(info, actual.hasSum(), true); - String prefix = monotonic ? "monotonic" : "non-monotonic"; - info.description(prefix + " sum expected for metric '%s'", actual.getName()); + String sumType = monotonic ? "monotonic" : "non-monotonic"; + info.description("sum for metric '%s' is expected to be %s", actual.getName(), sumType); objects.assertEqual(info, actual.getSum().getIsMonotonic(), monotonic); return this; } @@ -156,6 +155,11 @@ public MetricAssert isUpDownCounter() { return this; } + /** + * Verifies that there is no attribute in any of data points. + * + * @return this + */ @CanIgnoreReturnValue public MetricAssert hasDataPointsWithoutAttributes() { isNotNull(); @@ -195,6 +199,7 @@ private MetricAssert checkDataPoints(Consumer> listConsume return this; } + // TODO: To be removed and calls will be replaced with hasDataPointsWithAttributes() @CanIgnoreReturnValue public MetricAssert hasTypedDataPoints(Collection types) { return checkDataPoints( @@ -229,58 +234,40 @@ private void dataPointsCommonCheck(List dataPoints) { } /** - * Verifies that all data points have all the expected attributes + * Verifies that all data points have the same expected one attribute * - * @param attributes expected attributes + * @param expectedAttribute expected attribute * @return this */ - @SafeVarargs @CanIgnoreReturnValue - public final MetricAssert hasDataPointsAttributes(Map.Entry... attributes) { - return checkDataPoints( - dataPoints -> { - dataPointsCommonCheck(dataPoints); - - Map attributesMap = new HashMap<>(); - for (Map.Entry attributeEntry : attributes) { - attributesMap.put(attributeEntry.getKey(), attributeEntry.getValue()); - } - for (NumberDataPoint dataPoint : dataPoints) { - Map dataPointAttributes = toMap(dataPoint.getAttributesList()); - - // all attributes must match - info.description( - "missing/unexpected data points attributes for metric '%s'", actual.getName()); - containsExactly(dataPointAttributes, attributes); - maps.assertContainsAllEntriesOf(info, dataPointAttributes, attributesMap); - } - }); + public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expectedAttribute) { + return hasDataPointsWithAttributes(Collections.singleton(expectedAttribute)); } /** - * Verifies that all data points have their attributes match one of the attributes set and that - * all provided attributes sets matched at least once. + * Verifies that every provided attribute matcher set matches attributes of at least one metric + * data point. Attribute matcher set is considered matching data point attributes if each matcher + * matches exactly one data point attribute * - * @param attributeSets sets of attributes as maps + * @param attributeSets array of attribute matcher sets * @return this */ @SafeVarargs @CanIgnoreReturnValue @SuppressWarnings("varargs") // required to avoid warning - public final MetricAssert hasDataPointsAttributes(Map... attributeSets) { + public final MetricAssert hasDataPointsWithAttributes(Set... attributeSets) { return checkDataPoints( dataPoints -> { dataPointsCommonCheck(dataPoints); boolean[] matchedSets = new boolean[attributeSets.length]; - // validate each datapoint attributes match exactly one of the provided attributes set + // validate each datapoint attributes match exactly one of the provided attributes sets for (NumberDataPoint dataPoint : dataPoints) { - Map map = toMap(dataPoint.getAttributesList()); - + Set dataPointAttributes = toSet(dataPoint.getAttributesList()); int matchCount = 0; for (int i = 0; i < attributeSets.length; i++) { - if (mapEquals(map, attributeSets[i])) { + if (attributeSets[i].equals(dataPointAttributes)) { matchedSets[i] = true; matchCount++; } @@ -288,7 +275,7 @@ public final MetricAssert hasDataPointsAttributes(Map... attribu info.description( "data point attributes '%s' for metric '%s' must match exactly one of the attribute sets '%s'", - map, actual.getName(), Arrays.asList(attributeSets)); + dataPointAttributes, actual.getName(), Arrays.asList(attributeSets)); integers.assertEqual(info, matchCount, 1); } @@ -302,29 +289,9 @@ public final MetricAssert hasDataPointsAttributes(Map... attribu }); } - /** - * Map equality utility - * - * @param m1 first map - * @param m2 second map - * @return true if the maps have exactly the same keys and values - */ - private static boolean mapEquals(Map m1, Map m2) { - if (m1.size() != m2.size()) { - return false; - } - return m1.entrySet().stream().allMatch(e -> e.getValue().equals(m2.get(e.getKey()))); - } - - @SafeVarargs - @SuppressWarnings("varargs") // required to avoid warning - private final void containsExactly( - Map map, Map.Entry... entries) { - maps.assertContainsExactly(info, map, entries); - } - - private static Map toMap(List list) { + private static Set toSet(List list) { return list.stream() - .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); + .map(entry -> attribute(entry.getKey(), entry.getValue().getStringValue())) + .collect(Collectors.toSet()); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index a5c5522bf..dc35d4af5 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -5,7 +5,8 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static org.assertj.core.api.Assertions.entry; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import java.nio.file.Path; @@ -46,9 +47,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of consumers currently reading from the broker.") .hasUnit("{consumer}") .isUpDownCounter() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.producer.count", metric -> @@ -56,9 +58,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of producers currently attached to the broker.") .hasUnit("{producer}") .isUpDownCounter() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.connection.count", metric -> @@ -66,7 +69,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The total number of current connections.") .hasUnit("{connection}") .isUpDownCounter() - .hasDataPointsAttributes(entry("broker", "localhost"))) + .hasDataPointsWithOneAttribute(attribute("broker", "localhost"))) .add( "activemq.memory.usage", metric -> @@ -74,9 +77,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The percentage of configured memory used.") .hasUnit("%") .isGauge() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.disk.store_usage", metric -> @@ -85,7 +89,7 @@ protected MetricsVerifier createMetricsVerifier() { "The percentage of configured disk used for persistent messages.") .hasUnit("%") .isGauge() - .hasDataPointsAttributes(entry("broker", "localhost"))) + .hasDataPointsWithOneAttribute(attribute("broker", "localhost"))) .add( "activemq.disk.temp_usage", metric -> @@ -94,7 +98,7 @@ protected MetricsVerifier createMetricsVerifier() { "The percentage of configured disk used for non-persistent messages.") .hasUnit("%") .isGauge() - .hasDataPointsAttributes(entry("broker", "localhost"))) + .hasDataPointsWithOneAttribute(attribute("broker", "localhost"))) .add( "activemq.message.current", metric -> @@ -102,9 +106,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The current number of messages waiting to be consumed.") .hasUnit("{message}") .isUpDownCounter() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.message.expired", metric -> @@ -113,9 +118,10 @@ protected MetricsVerifier createMetricsVerifier() { "The total number of messages not delivered because they expired.") .hasUnit("{message}") .isCounter() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.message.enqueued", metric -> @@ -123,9 +129,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The total number of messages received by the broker.") .hasUnit("{message}") .isCounter() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.message.dequeued", metric -> @@ -133,9 +140,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The total number of messages delivered to consumers.") .hasUnit("{message}") .isCounter() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))) + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))) .add( "activemq.message.wait_time.avg", metric -> @@ -143,8 +151,9 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The average time a message was held on a destination.") .hasUnit("ms") .isGauge() - .hasDataPointsAttributes( - entry("destination", "ActiveMQ.Advisory.MasterBroker"), - entry("broker", "localhost"))); + .hasDataPointsWithAttributes( + attributeSet( + attribute("destination", "ActiveMQ.Advisory.MasterBroker"), + attribute("broker", "localhost")))); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java index a16b4a6a0..e72c904ee 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java @@ -5,11 +5,14 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; + import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; +import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcher; import java.nio.file.Path; import java.time.Duration; -import java.util.HashMap; -import java.util.Map; +import java.util.Set; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -158,10 +161,10 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("Number of requests by operation") .hasUnit("1") .isCounter() - .hasDataPointsAttributes( - requestCountAttributes("RangeSlice"), - requestCountAttributes("Read"), - requestCountAttributes("Write"))) + .hasDataPointsWithAttributes( + attributeSet(attribute("operation", "RangeSlice")), + attributeSet(attribute("operation", "Read")), + attributeSet(attribute("operation", "Write")))) .add( "cassandra.client.request.error.count", metric -> @@ -169,7 +172,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("Number of request errors by operation") .hasUnit("1") .isCounter() - .hasDataPointsAttributes( + .hasDataPointsWithAttributes( errorCountAttributes("RangeSlice", "Timeout"), errorCountAttributes("RangeSlice", "Failure"), errorCountAttributes("RangeSlice", "Unavailable"), @@ -181,16 +184,7 @@ protected MetricsVerifier createMetricsVerifier() { errorCountAttributes("Write", "Unavailable"))); } - private static Map errorCountAttributes(String operation, String status) { - Map map = new HashMap<>(); - map.put("operation", operation); - map.put("status", status); - return map; - } - - private static Map requestCountAttributes(String operation) { - Map map = new HashMap<>(); - map.put("operation", operation); - return map; + private static Set errorCountAttributes(String operation, String status) { + return attributeSet(attribute("operation", operation), attribute("status", status)); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java index 93877e279..ba2158c81 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java @@ -5,11 +5,9 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGauge; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGaugeWithAttributes; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSum; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSumWithAttributes; -import static org.assertj.core.data.MapEntry.entry; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import java.nio.file.Path; @@ -36,404 +34,492 @@ protected JmxScraperContainer customizeScraperContainer( } @Override - protected void verifyMetrics() { - waitAndAssertMetrics( - metric -> - assertSumWithAttributes( - metric, - "hbase.master.region_server.count", - "The number of region servers.", - "{server}", - /* isMonotonic= */ false, - attrs -> attrs.contains(entry("state", "dead")), - attrs -> attrs.contains(entry("state", "live"))), - metric -> - assertSum( - metric, - "hbase.master.regions_in_transition.count", - "The number of regions that are in transition.", - "{region}", - /* isMonotonic= */ false), - metric -> - assertSum( - metric, - "hbase.master.regions_in_transition.over_threshold", - "The number of regions that have been in transition longer than a threshold time.", - "{region}", - /* isMonotonic= */ false), - metric -> - assertGauge( - metric, - "hbase.master.regions_in_transition.oldest_age", - "The age of the longest region in transition.", - "ms"), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.region.count", - "The number of regions hosted by the region server.", - "{region}", - /* isMonotonic= */ false, - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.disk.store_file.count", - "The number of store files on disk currently managed by the region server.", - "{file}", - /* isMonotonic= */ false, - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.disk.store_file.size", - "Aggregate size of the store files on disk.", - "By", - /* isMonotonic= */ false, - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.write_ahead_log.count", - "The number of write ahead logs not yet archived.", - "{log}", - /* isMonotonic= */ false, - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.request.count", - "The number of requests received.", - "{request}", - /* isMonotonic= */ false, - attrs -> { - attrs.contains(entry("state", "write")); - attrs.containsKey("region_server"); - }, - attrs -> { - attrs.contains(entry("state", "read")); - attrs.containsKey("region_server"); - }), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.queue.length", - "The number of RPC handlers actively servicing requests.", - "{handler}", - /* isMonotonic= */ false, - attrs -> { - attrs.contains(entry("state", "flush")); - attrs.containsKey("region_server"); - }, - attrs -> { - attrs.contains(entry("state", "compaction")); - attrs.containsKey("region_server"); - }), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.blocked_update.time", - "Amount of time updates have been blocked so the memstore can be flushed.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.block_cache.operation.count", - "Number of block cache hits/misses.", - "{operation}", - attrs -> { - attrs.contains(entry("state", "miss")); - attrs.containsKey("region_server"); - }, - attrs -> { - attrs.contains(entry("state", "hit")); - attrs.containsKey("region_server"); - }), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.files.local", - "Percent of store file data that can be read from the local.", - "%", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.append.latency.p99", - "Append operation 99th Percentile latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.append.latency.max", - "Append operation max latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.append.latency.min", - "Append operation minimum latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.append.latency.mean", - "Append operation mean latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.append.latency.median", - "Append operation median latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.delete.latency.p99", - "Delete operation 99th Percentile latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.delete.latency.max", - "Delete operation max latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.delete.latency.min", - "Delete operation minimum latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.delete.latency.mean", - "Delete operation mean latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.delete.latency.median", - "Delete operation median latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.put.latency.p99", - "Put operation 99th Percentile latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.put.latency.max", - "Put operation max latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.put.latency.min", - "Put operation minimum latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.put.latency.mean", - "Put operation mean latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.put.latency.median", - "Put operation median latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.get.latency.p99", - "Get operation 99th Percentile latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.get.latency.max", - "Get operation max latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.get.latency.min", - "Get operation minimum latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.get.latency.mean", - "Get operation mean latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.get.latency.median", - "Get operation median latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.replay.latency.p99", - "Replay operation 99th Percentile latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.replay.latency.max", - "Replay operation max latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.replay.latency.min", - "Replay operation minimum latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.replay.latency.mean", - "Replay operation mean latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.replay.latency.median", - "Replay operation median latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.increment.latency.p99", - "Increment operation 99th Percentile latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.increment.latency.max", - "Increment operation max latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.increment.latency.min", - "Increment operation minimum latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.increment.latency.mean", - "Increment operation mean latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertGaugeWithAttributes( - metric, - "hbase.region_server.operation.increment.latency.median", - "Increment operation median latency.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.operations.slow", - "Number of operations that took over 1000ms to complete.", - "{operation}", - /* isMonotonic= */ false, - attrs -> attrs.contains(entry("operation", "delete")), - attrs -> attrs.contains(entry("operation", "append")), - attrs -> attrs.contains(entry("operation", "get")), - attrs -> attrs.contains(entry("operation", "put")), - attrs -> attrs.contains(entry("operation", "increment"))), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.open_connection.count", - "The number of open connections at the RPC layer.", - "{connection}", - /* isMonotonic= */ false, - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.active_handler.count", - "The number of RPC handlers actively servicing requests.", - "{handler}", - /* isMonotonic= */ false, - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.queue.request.count", - "The number of currently enqueued requests.", - "{request}", - /* isMonotonic= */ false, - attrs -> attrs.contains(entry("state", "replication")), - attrs -> attrs.contains(entry("state", "user")), - attrs -> attrs.contains(entry("state", "priority"))), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.authentication.count", - "Number of client connection authentication failures/successes.", - "{authentication request}", - /* isMonotonic= */ false, - attrs -> attrs.contains(entry("state", "successes")), - attrs -> attrs.contains(entry("state", "failures"))), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.gc.time", - "Time spent in garbage collection.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.gc.young_gen.time", - "Time spent in garbage collection of the young generation.", - "ms", - attrs -> attrs.containsKey("region_server")), - metric -> - assertSumWithAttributes( - metric, - "hbase.region_server.gc.old_gen.time", - "Time spent in garbage collection of the old generation.", - "ms", - attrs -> attrs.containsKey("region_server"))); + protected MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create() + .disableStrictMode() + .add( + "hbase.master.region_server.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of region servers.") + .hasUnit("{server}") + .hasDataPointsWithAttributes( + attributeSet(attribute("state", "dead")), + attributeSet(attribute("state", "live")))) + .add( + "hbase.master.regions_in_transition.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of region servers.") + .hasUnit("{server}") + .hasDataPointsWithoutAttributes()) + .add( + "hbase.master.regions_in_transition.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of regions that are in transition.") + .hasUnit("{region}") + .hasDataPointsWithoutAttributes()) + .add( + "hbase.master.regions_in_transition.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of regions that are in transition.") + .hasUnit("{region}") + .hasDataPointsWithoutAttributes()) + .add( + "hbase.master.regions_in_transition.over_threshold", + metric -> + metric + .isUpDownCounter() + .hasDescription( + "The number of regions that have been in transition longer than a threshold time.") + .hasUnit("{region}") + .hasDataPointsWithoutAttributes()) + .add( + "hbase.master.regions_in_transition.oldest_age", + metric -> + metric + .isGauge() + .hasDescription("The age of the longest region in transition.") + .hasUnit("ms") + .hasDataPointsWithoutAttributes()) + .add( + "hbase.region_server.region.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of regions hosted by the region server.") + .hasUnit("{region}") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.disk.store_file.count", + metric -> + metric + .isUpDownCounter() + .hasDescription( + "The number of store files on disk currently managed by the region server.") + .hasUnit("{file}") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.disk.store_file.size", + metric -> + metric + .isUpDownCounter() + .hasDescription("Aggregate size of the store files on disk.") + .hasUnit("By") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.write_ahead_log.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of write ahead logs not yet archived.") + .hasUnit("{log}") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.request.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of requests received.") + .hasUnit("{request}") + .hasDataPointsWithAttributes( + attributeSet( + attribute("state", "write"), attributeWithAnyValue("region_server")), + attributeSet( + attribute("state", "read"), attributeWithAnyValue("region_server")))) + .add( + "hbase.region_server.queue.length", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of RPC handlers actively servicing requests.") + .hasUnit("{handler}") + .hasDataPointsWithAttributes( + attributeSet( + attribute("state", "flush"), attributeWithAnyValue("region_server")), + attributeSet( + attribute("state", "compaction"), + attributeWithAnyValue("region_server")))) + .add( + "hbase.region_server.blocked_update.time", + metric -> + metric + .isGauge() + .hasDescription( + "Amount of time updates have been blocked so the memstore can be flushed.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.block_cache.operation.count", + metric -> + metric + .isGauge() + .hasDescription("Number of block cache hits/misses.") + .hasUnit("{operation}") + .hasDataPointsWithAttributes( + attributeSet( + attribute("state", "miss"), attributeWithAnyValue("region_server")), + attributeSet( + attribute("state", "hit"), attributeWithAnyValue("region_server")))) + .add( + "hbase.region_server.files.local", + metric -> + metric + .isGauge() + .hasDescription("Percent of store file data that can be read from the local.") + .hasUnit("%") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + + // Operation: append --------------------------------------------------------------------- + .add( + "hbase.region_server.operation.append.latency.p99", + metric -> + metric + .isGauge() + .hasDescription("Append operation 99th Percentile latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.append.latency.max", + metric -> + metric + .isGauge() + .hasDescription("Append operation max latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.append.latency.min", + metric -> + metric + .isGauge() + .hasDescription("Append operation minimum latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.append.latency.mean", + metric -> + metric + .isGauge() + .hasDescription("Append operation mean latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.append.latency.median", + metric -> + metric + .isGauge() + .hasDescription("Append operation median latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + + // Operation: delete --------------------------------------------------------------------- + .add( + "hbase.region_server.operation.delete.latency.p99", + metric -> + metric + .isGauge() + .hasDescription("Delete operation 99th Percentile latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.delete.latency.max", + metric -> + metric + .isGauge() + .hasDescription("Delete operation max latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.delete.latency.min", + metric -> + metric + .isGauge() + .hasDescription("Delete operation minimum latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.delete.latency.mean", + metric -> + metric + .isGauge() + .hasDescription("Delete operation mean latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.delete.latency.median", + metric -> + metric + .isGauge() + .hasDescription("Delete operation median latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + + // Operation: put --------------------------------------------------------------------- + .add( + "hbase.region_server.operation.put.latency.p99", + metric -> + metric + .isGauge() + .hasDescription("Put operation 99th Percentile latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.put.latency.max", + metric -> + metric + .isGauge() + .hasDescription("Put operation max latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.put.latency.min", + metric -> + metric + .isGauge() + .hasDescription("Put operation minimum latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.put.latency.mean", + metric -> + metric + .isGauge() + .hasDescription("Put operation mean latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.put.latency.median", + metric -> + metric + .isGauge() + .hasDescription("Put operation median latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + + // Operation: get --------------------------------------------------------------------- + .add( + "hbase.region_server.operation.get.latency.p99", + metric -> + metric + .isGauge() + .hasDescription("Get operation 99th Percentile latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.get.latency.max", + metric -> + metric + .isGauge() + .hasDescription("Get operation max latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.get.latency.min", + metric -> + metric + .isGauge() + .hasDescription("Get operation minimum latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.get.latency.mean", + metric -> + metric + .isGauge() + .hasDescription("Get operation mean latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.get.latency.median", + metric -> + metric + .isGauge() + .hasDescription("Get operation median latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + + // Operation: replay --------------------------------------------------------------------- + .add( + "hbase.region_server.operation.replay.latency.p99", + metric -> + metric + .isGauge() + .hasDescription("Replay operation 99th Percentile latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.replay.latency.max", + metric -> + metric + .isGauge() + .hasDescription("Replay operation max latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.replay.latency.min", + metric -> + metric + .isGauge() + .hasDescription("Replay operation minimum latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.replay.latency.mean", + metric -> + metric + .isGauge() + .hasDescription("Replay operation mean latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.replay.latency.median", + metric -> + metric + .isGauge() + .hasDescription("Replay operation median latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + + // Operation: increment ------------------------------------------------------------------- + .add( + "hbase.region_server.operation.increment.latency.p99", + metric -> + metric + .isGauge() + .hasDescription("Increment operation 99th Percentile latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.increment.latency.max", + metric -> + metric + .isGauge() + .hasDescription("Increment operation max latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.increment.latency.min", + metric -> + metric + .isGauge() + .hasDescription("Increment operation minimum latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.increment.latency.mean", + metric -> + metric + .isGauge() + .hasDescription("Increment operation mean latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.operation.increment.latency.median", + metric -> + metric + .isGauge() + .hasDescription("Increment operation median latency.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + // ----------------------------------------------------------------------------------- + + .add( + "hbase.region_server.operations.slow", + metric -> + metric + .isUpDownCounter() + .hasDescription("Number of operations that took over 1000ms to complete.") + .hasUnit("{operation}") + .hasDataPointsWithAttributes( + attributeSet( + attribute("operation", "delete"), + attributeWithAnyValue("region_server")), + attributeSet( + attribute("operation", "append"), + attributeWithAnyValue("region_server")), + attributeSet( + attribute("operation", "get"), attributeWithAnyValue("region_server")), + attributeSet( + attribute("operation", "put"), attributeWithAnyValue("region_server")), + attributeSet( + attribute("operation", "increment"), + attributeWithAnyValue("region_server")))) + .add( + "hbase.region_server.open_connection.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of open connections at the RPC layer.") + .hasUnit("{connection}") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.active_handler.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of RPC handlers actively servicing requests.") + .hasUnit("{handler}") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.queue.request.count", + metric -> + metric + .isUpDownCounter() + .hasDescription("The number of currently enqueued requests.") + .hasUnit("{request}") + .hasDataPointsWithAttributes( + attributeSet( + attribute("state", "replication"), + attributeWithAnyValue("region_server")), + attributeSet( + attribute("state", "user"), attributeWithAnyValue("region_server")), + attributeSet( + attribute("state", "priority"), + attributeWithAnyValue("region_server")))) + .add( + "hbase.region_server.authentication.count", + metric -> + metric + .isUpDownCounter() + .hasDescription( + "Number of client connection authentication failures/successes.") + .hasUnit("{authentication request}") + .hasDataPointsWithAttributes( + attributeSet( + attribute("state", "successes"), + attributeWithAnyValue("region_server")), + attributeSet( + attribute("state", "failures"), + attributeWithAnyValue("region_server")))) + .add( + "hbase.region_server.gc.time", + metric -> + metric + .isCounter() + .hasDescription("Time spent in garbage collection.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.gc.young_gen.time", + metric -> + metric + .isCounter() + .hasDescription("Time spent in garbage collection of the young generation.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))) + .add( + "hbase.region_server.gc.old_gen.time", + metric -> + metric + .isCounter() + .hasDescription("Time spent in garbage collection of the old generation.") + .hasUnit("ms") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("region_server"))); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java index fb1f489b1..ed44316b9 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java @@ -5,10 +5,9 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGauge; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGaugeWithAttributes; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSumWithAttributes; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSumWithAttributesMultiplePoints; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import java.nio.file.Path; @@ -55,51 +54,60 @@ protected JmxScraperContainer customizeScraperContainer( } @Override - protected void verifyMetrics() { - waitAndAssertMetrics( - metric -> - assertSumWithAttributes( - metric, - "jetty.session.count", - "The number of sessions established in total.", - "{session}", - attrs -> attrs.containsKey("resource")), - metric -> - assertSumWithAttributes( - metric, - "jetty.session.time.total", - "The total time sessions have been active.", - "s", - attrs -> attrs.containsKey("resource")), - metric -> - assertGaugeWithAttributes( - metric, - "jetty.session.time.max", - "The maximum amount of time a session has been active.", - "s", - attrs -> attrs.containsKey("resource")), - metric -> - assertSumWithAttributesMultiplePoints( - metric, - "jetty.select.count", - "The number of select calls.", - "{operation}", - /* isMonotonic= */ true, - // minor divergence from jetty.groovy with extra metrics attributes - attrs -> attrs.containsKey("context").containsKey("id")), - metric -> - assertGaugeWithAttributes( - metric, - "jetty.thread.count", - "The current number of threads.", - "{thread}", - attrs -> attrs.containsEntry("state", "busy"), - attrs -> attrs.containsEntry("state", "idle")), - metric -> - assertGauge( - metric, - "jetty.thread.queue.count", - "The current number of threads in the queue.", - "{thread}")); + protected MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create() + .add( + "jetty.session.count", + metric -> + metric + .isCounter() + .hasDescription("The number of sessions established in total.") + .hasUnit("{session}") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("resource"))) + .add( + "jetty.session.time.total", + metric -> + metric + .isCounter() + .hasDescription("The total time sessions have been active.") + .hasUnit("s") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("resource"))) + .add( + "jetty.session.time.max", + metric -> + metric + .isGauge() + .hasDescription("The maximum amount of time a session has been active.") + .hasUnit("s") + .hasDataPointsWithOneAttribute(attributeWithAnyValue("resource"))) + .add( + "jetty.select.count", + metric -> + metric + .isCounter() + .hasDescription("The number of select calls.") + .hasUnit("{operation}") + .hasDataPointsWithAttributes( + attributeSet( + attributeWithAnyValue("context"), attributeWithAnyValue("id")))) + .add( + "jetty.thread.count", + metric -> + metric + .isGauge() + .hasDescription("The current number of threads.") + .hasUnit("{thread}") + .hasDataPointsWithAttributes( + attributeSet(attribute("state", "busy")), + attributeSet(attribute("state", "idle")))) + .add( + "jetty.thread.queue.count", + metric -> + metric + .isGauge() + .hasDescription("The current number of threads in the queue.") + .hasUnit("{thread}") + .hasDataPointsWithoutAttributes() // Got rid of id (see jetty.yaml) + ); } } From b26cf42077a62202178bacdb44ad42af18a4e12f Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 4 Dec 2024 16:15:23 +0100 Subject: [PATCH 32/53] Coe review changes --- .../assertions/AttributeMatcher.java | 61 ++++++++++++------- .../assertions/AttributeValueMatcher.java | 41 ------------- .../assertions/DataPointAttributes.java | 32 +++++++++- .../jmxscraper/assertions/MetricAssert.java | 52 ++++++++++------ .../target_systems/HBaseIntegrationTest.java | 1 - 5 files changed, 102 insertions(+), 85 deletions(-) delete mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index fdb63d3d6..e99e0dee8 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -5,38 +5,41 @@ package io.opentelemetry.contrib.jmxscraper.assertions; -import static io.opentelemetry.contrib.jmxscraper.assertions.AttributeValueMatcher.ANY_VALUE_MATCHER; - import java.util.Objects; /** Implements functionality of matching data point attributes. */ public class AttributeMatcher { - private final String name; - private final AttributeValueMatcher attributeValueMatcher; + private final String attributeName; + private final String attributeValue; /** - * Create instance used to match data point attribute with te same name and with any value. + * Create instance used to match data point attribute with any value. * - * @param name attribute name + * @param attributeName matched attribute name */ - AttributeMatcher(String name) { - this.name = name; - this.attributeValueMatcher = ANY_VALUE_MATCHER; + AttributeMatcher(String attributeName) { + this.attributeName = attributeName; + this.attributeValue = null; } /** * Create instance used to match data point attribute with te same name and with the same value. * - * @param name attribute name - * @param value attribute value + * @param attributeName attribute name + * @param attributeValue attribute value */ - AttributeMatcher(String name, String value) { - this.name = name; - this.attributeValueMatcher = new AttributeValueMatcher(value); + AttributeMatcher(String attributeName, String attributeValue) { + this.attributeName = attributeName; + this.attributeValue = attributeValue; } - public String getName() { - return name; + /** + * Return name of data point attribute that this AttributeMatcher is supposed to match value with. + * + * @return name of validated attribute + */ + public String getAttributeName() { + return attributeName; } @Override @@ -48,21 +51,33 @@ public boolean equals(Object o) { return false; } AttributeMatcher other = (AttributeMatcher) o; - return Objects.equals(name, other.name) - && attributeValueMatcher.matchValue(other.attributeValueMatcher); + return Objects.equals(attributeName, other.attributeName); } @Override public int hashCode() { // Do not use value matcher here to support value wildcards - return Objects.hash(name); + return Objects.hash(attributeName); } @Override public String toString() { - return attributeValueMatcher.getValue() == null - ? '{' + name + '}' - : '{' + name + '=' + attributeValueMatcher.getValue() + '}'; + return attributeValue == null + ? '{' + attributeName + '}' + : '{' + attributeName + '=' + attributeValue + '}'; + } + + /** + * Verify if this matcher is matching provided attribute value. If this matcher holds null value + * then it is matching any attribute value + * + * @param value a value to be matched + * @return true if this matcher is matching provided value, false otherwise. + */ + boolean matchesValue(String value) { + if ((attributeValue == null) || (value == null)) { + return true; + } + return Objects.equals(attributeValue, value); } - ; } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java deleted file mode 100644 index 6eea6cbd5..000000000 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeValueMatcher.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.jmxscraper.assertions; - -import java.util.Objects; - -class AttributeValueMatcher { - static final AttributeValueMatcher ANY_VALUE_MATCHER = new AttributeValueMatcher(); - - private final String value; - - AttributeValueMatcher() { - this(null); - } - - AttributeValueMatcher(String value) { - this.value = value; - } - - String getValue() { - return value; - } - - /** - * Match the value held by this and the other AttributeValueMatcher instances. Null value means - * "any value", that's why if any of the values is null they are considered as matching. If both - * values are not null then they must be equal. - * - * @param other the other matcher to compare value with - * @return true if values held by both matchers are matching, false otherwise. - */ - boolean matchValue(AttributeValueMatcher other) { - if ((value == null) || (other.value == null)) { - return true; - } - return Objects.equals(value, other.value); - } -} diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java index 7b0f40e1a..9897169cf 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java @@ -16,15 +16,45 @@ public class DataPointAttributes { private DataPointAttributes() {} + /** + * Create instance of matcher that will be used to check if data point attribute with given name + * has provided value. + * + * @param name name of the data point attribute to check + * @param value expected value of data point attribute + * @return instance of matcher + */ public static AttributeMatcher attribute(String name, String value) { return new AttributeMatcher(name, value); } + /** + * Create instance of matcher that will be used to check if data point attribute with given name + * exists. Any value of the attribute is considered as matching. + * + * @param name name of the data point attribute to check + * @return instance of matcher + */ public static AttributeMatcher attributeWithAnyValue(String name) { return new AttributeMatcher(name); } + /** + * Create a set of attribute matchers that will be used to verify set of data point attributes. + * + * @param attributes list of matchers to create set. It must contain matchers with unique names. + * @return set of unique attribute matchers + * @throws IllegalArgumentException if provided list contains two or more matchers with the same + * name. + * @see MetricAssert#hasDataPointsWithAttributes(Set[]) for detailed description of the algorithm + * of matching + */ public static Set attributeSet(AttributeMatcher... attributes) { - return Arrays.stream(attributes).collect(Collectors.toSet()); + Set matcherSet = Arrays.stream(attributes).collect(Collectors.toSet()); + if (matcherSet.size() < attributes.length) { + throw new IllegalArgumentException( + "Duplicated matchers found in " + Arrays.toString(attributes)); + } + return matcherSet; } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 307874b78..8542d87fc 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -5,7 +5,7 @@ package io.opentelemetry.contrib.jmxscraper.assertions; -import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.proto.common.v1.KeyValue; @@ -13,9 +13,9 @@ import io.opentelemetry.proto.metrics.v1.NumberDataPoint; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -234,40 +234,41 @@ private void dataPointsCommonCheck(List dataPoints) { } /** - * Verifies that all data points have the same expected one attribute + * Verifies that all metric data points have the same expected one attribute * - * @param expectedAttribute expected attribute + * @param expectedAttribute attribute matcher to validate data points attributes * @return this */ @CanIgnoreReturnValue public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expectedAttribute) { - return hasDataPointsWithAttributes(Collections.singleton(expectedAttribute)); + return hasDataPointsWithAttributes(attributeSet(expectedAttribute)); } /** - * Verifies that every provided attribute matcher set matches attributes of at least one metric - * data point. Attribute matcher set is considered matching data point attributes if each matcher - * matches exactly one data point attribute + * Verifies that every data point attributes set is matched by one of matcher sets provided. Data + * point attributes set is matched by matcher set if each attribute is matched by one matcher and + * matcher count is equal to attribute count. * - * @param attributeSets array of attribute matcher sets + * @param attributeMatchers array of attribute matcher sets * @return this */ @SafeVarargs @CanIgnoreReturnValue @SuppressWarnings("varargs") // required to avoid warning - public final MetricAssert hasDataPointsWithAttributes(Set... attributeSets) { + public final MetricAssert hasDataPointsWithAttributes( + Set... attributeMatchers) { return checkDataPoints( dataPoints -> { dataPointsCommonCheck(dataPoints); - boolean[] matchedSets = new boolean[attributeSets.length]; + boolean[] matchedSets = new boolean[attributeMatchers.length]; // validate each datapoint attributes match exactly one of the provided attributes sets for (NumberDataPoint dataPoint : dataPoints) { - Set dataPointAttributes = toSet(dataPoint.getAttributesList()); + Map dataPointAttributes = toMap(dataPoint.getAttributesList()); int matchCount = 0; - for (int i = 0; i < attributeSets.length; i++) { - if (attributeSets[i].equals(dataPointAttributes)) { + for (int i = 0; i < attributeMatchers.length; i++) { + if (matchAttributes(attributeMatchers[i], dataPointAttributes)) { matchedSets[i] = true; matchCount++; } @@ -275,7 +276,7 @@ public final MetricAssert hasDataPointsWithAttributes(Set... a info.description( "data point attributes '%s' for metric '%s' must match exactly one of the attribute sets '%s'", - dataPointAttributes, actual.getName(), Arrays.asList(attributeSets)); + dataPointAttributes, actual.getName(), Arrays.asList(attributeMatchers)); integers.assertEqual(info, matchCount, 1); } @@ -283,15 +284,28 @@ public final MetricAssert hasDataPointsWithAttributes(Set... a for (int i = 0; i < matchedSets.length; i++) { info.description( "no data point matched attribute set '%s' for metric '%s'", - attributeSets[i], actual.getName()); + attributeMatchers[i], actual.getName()); objects.assertEqual(info, matchedSets[i], true); } }); } - private static Set toSet(List list) { + private static boolean matchAttributes( + Set attributeMatchers, Map dataPointAttributes) { + if (attributeMatchers.size() != dataPointAttributes.size()) { + return false; + } + for (AttributeMatcher matcher : attributeMatchers) { + String attributeValue = dataPointAttributes.get(matcher.getAttributeName()); + if (!matcher.matchesValue(attributeValue)) { + return false; + } + } + return true; + } + + private static Map toMap(List list) { return list.stream() - .map(entry -> attribute(entry.getKey(), entry.getValue().getStringValue())) - .collect(Collectors.toSet()); + .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java index ba2158c81..bece18c33 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java @@ -36,7 +36,6 @@ protected JmxScraperContainer customizeScraperContainer( @Override protected MetricsVerifier createMetricsVerifier() { return MetricsVerifier.create() - .disableStrictMode() .add( "hbase.master.region_server.count", metric -> From 0bf10f57d9d8fe7e4ddfceede4d0e7176a918ad3 Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 4 Dec 2024 16:43:01 +0100 Subject: [PATCH 33/53] JavaDoc update --- .../contrib/jmxscraper/assertions/MetricAssert.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 8542d87fc..d093b4e82 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -245,9 +245,10 @@ public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expecte } /** - * Verifies that every data point attributes set is matched by one of matcher sets provided. Data - * point attributes set is matched by matcher set if each attribute is matched by one matcher and - * matcher count is equal to attribute count. + * Verifies that every data point attributes set is matched exactly by one of the matcher sets provided. + * Also, each matcher set must match at least one data point attributes set. + * Data point attributes set is matched by matcher set if each attribute is matched by one matcher and + * each matcher matches one attribute. * * @param attributeMatchers array of attribute matcher sets * @return this From 9f47ef6f512022d0d5056f280f0d69bf10f91b6e Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 4 Dec 2024 20:17:30 +0100 Subject: [PATCH 34/53] JavaDoc update --- .../jmxscraper/assertions/DataPointAttributes.java | 14 +++++++------- .../jmxscraper/assertions/MetricAssert.java | 9 +++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java index 9897169cf..ba8d7d016 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java @@ -17,11 +17,11 @@ public class DataPointAttributes { private DataPointAttributes() {} /** - * Create instance of matcher that will be used to check if data point attribute with given name - * has provided value. + * Create instance of matcher that should be used to check if data point attribute with given name + * has value identical to the one provided as a parameter (exact match). * * @param name name of the data point attribute to check - * @param value expected value of data point attribute + * @param value expected value of checked data point attribute * @return instance of matcher */ public static AttributeMatcher attribute(String name, String value) { @@ -29,8 +29,8 @@ public static AttributeMatcher attribute(String name, String value) { } /** - * Create instance of matcher that will be used to check if data point attribute with given name - * exists. Any value of the attribute is considered as matching. + * Create instance of matcher that should be used to check if data point attribute with given name + * exists. Any value of the attribute is considered as matching (any value match). * * @param name name of the data point attribute to check * @return instance of matcher @@ -40,14 +40,14 @@ public static AttributeMatcher attributeWithAnyValue(String name) { } /** - * Create a set of attribute matchers that will be used to verify set of data point attributes. + * Create a set of attribute matchers that should be used to verify set of data point attributes. * * @param attributes list of matchers to create set. It must contain matchers with unique names. * @return set of unique attribute matchers * @throws IllegalArgumentException if provided list contains two or more matchers with the same * name. * @see MetricAssert#hasDataPointsWithAttributes(Set[]) for detailed description of the algorithm - * of matching + * used for matching */ public static Set attributeSet(AttributeMatcher... attributes) { Set matcherSet = Arrays.stream(attributes).collect(Collectors.toSet()); diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index d093b4e82..94a53444f 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -245,10 +245,11 @@ public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expecte } /** - * Verifies that every data point attributes set is matched exactly by one of the matcher sets provided. - * Also, each matcher set must match at least one data point attributes set. - * Data point attributes set is matched by matcher set if each attribute is matched by one matcher and - * each matcher matches one attribute. + * Verifies that every data point attributes set is matched exactly by one of the matcher sets + * provided. Also, each matcher set must match at least one data point attributes set. Data point + * attributes set is matched by matcher set if each attribute is matched by one matcher and each + * matcher matches one attribute. In other words: number of attributes is the same as number of + * matchers and there is 1:1 matching between them. * * @param attributeMatchers array of attribute matcher sets * @return this From 2971ef7239d0d51f38c1a109c84ed1ad40862b03 Mon Sep 17 00:00:00 2001 From: Robert Niedziela <175605712+robsunday@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:18:18 +0100 Subject: [PATCH 35/53] Update jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java Co-authored-by: jason plumb <75337021+breedx-splk@users.noreply.github.com> --- .../contrib/jmxscraper/assertions/AttributeMatcher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index e99e0dee8..55b13cbb9 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -10,6 +10,7 @@ /** Implements functionality of matching data point attributes. */ public class AttributeMatcher { private final String attributeName; + @Nullable private final String attributeValue; /** From 7d7e5045784c7f344a72bd1f72671d1432c3f0d5 Mon Sep 17 00:00:00 2001 From: robsunday Date: Thu, 5 Dec 2024 10:04:12 +0100 Subject: [PATCH 36/53] Code review changes --- .../jmxscraper/assertions/AttributeMatcher.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index 55b13cbb9..8e7c4a3f9 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -6,12 +6,12 @@ package io.opentelemetry.contrib.jmxscraper.assertions; import java.util.Objects; +import javax.annotation.Nullable; /** Implements functionality of matching data point attributes. */ public class AttributeMatcher { private final String attributeName; - @Nullable - private final String attributeValue; + @Nullable private final String attributeValue; /** * Create instance used to match data point attribute with any value. @@ -19,8 +19,7 @@ public class AttributeMatcher { * @param attributeName matched attribute name */ AttributeMatcher(String attributeName) { - this.attributeName = attributeName; - this.attributeValue = null; + this(attributeName, null); } /** @@ -29,7 +28,7 @@ public class AttributeMatcher { * @param attributeName attribute name * @param attributeValue attribute value */ - AttributeMatcher(String attributeName, String attributeValue) { + AttributeMatcher(String attributeName, @Nullable String attributeValue) { this.attributeName = attributeName; this.attributeValue = attributeValue; } @@ -76,7 +75,7 @@ public String toString() { * @return true if this matcher is matching provided value, false otherwise. */ boolean matchesValue(String value) { - if ((attributeValue == null) || (value == null)) { + if (attributeValue == null) { return true; } return Objects.equals(attributeValue, value); From 19f5d4cfa1480609c0dcf425a0e495e1022423f1 Mon Sep 17 00:00:00 2001 From: robsunday Date: Thu, 5 Dec 2024 10:08:52 +0100 Subject: [PATCH 37/53] Cleanup --- .../contrib/jmxscraper/assertions/AttributeMatcher.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index 8e7c4a3f9..196c703db 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -56,7 +56,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - // Do not use value matcher here to support value wildcards return Objects.hash(attributeName); } @@ -69,15 +68,12 @@ public String toString() { /** * Verify if this matcher is matching provided attribute value. If this matcher holds null value - * then it is matching any attribute value + * then it is matching any attribute value. * * @param value a value to be matched * @return true if this matcher is matching provided value, false otherwise. */ boolean matchesValue(String value) { - if (attributeValue == null) { - return true; - } - return Objects.equals(attributeValue, value); + return (attributeValue == null) || Objects.equals(attributeValue, value); } } From 6431feb6c1d56d241a7bd7507f299fb9bf9f9430 Mon Sep 17 00:00:00 2001 From: robsunday Date: Thu, 5 Dec 2024 10:14:50 +0100 Subject: [PATCH 38/53] Additional comments added --- .../contrib/jmxscraper/assertions/AttributeMatcher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index 196c703db..6e6f17919 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -51,6 +51,8 @@ public boolean equals(Object o) { return false; } AttributeMatcher other = (AttributeMatcher) o; + // Do not attributeValue into account so AttributeMatcher instances can be stored in collections + // with guarantee of uniqueness per attribute return Objects.equals(attributeName, other.attributeName); } From ba0f9003e01843100fb0d5bc120054a2c0430048 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:21:02 +0100 Subject: [PATCH 39/53] add attribute matcher set class --- .../assertions/AttributeMatcherSet.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java new file mode 100644 index 000000000..2c884681b --- /dev/null +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.jmxscraper.assertions; + +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; + +/** Holder class for a set of attribute matchers */ +public class AttributeMatcherSet { + + // stored as a Map for easy lookup by name + private final Map matchers; + + /** + * Constructor for a set of attribute matchers + * + * @param matchers collection of matchers to build a set from + * @throws IllegalStateException if there is any duplicate key + */ + AttributeMatcherSet(Collection matchers) { + this.matchers = + matchers.stream().collect(Collectors.toMap(AttributeMatcher::getAttributeName, m -> m)); + } + + Map getMatchers() { + return matchers; + } + + @Override + public String toString() { + return matchers.values().toString(); + } +} From fdc64e3bb2d57c7468afc109296870a51c47b4d6 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:21:34 +0100 Subject: [PATCH 40/53] remove equals/hashcode --- .../assertions/AttributeMatcher.java | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index 55b13cbb9..ed2226131 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -6,12 +6,12 @@ package io.opentelemetry.contrib.jmxscraper.assertions; import java.util.Objects; +import javax.annotation.Nullable; /** Implements functionality of matching data point attributes. */ public class AttributeMatcher { private final String attributeName; - @Nullable - private final String attributeValue; + @Nullable private final String attributeValue; /** * Create instance used to match data point attribute with any value. @@ -29,7 +29,7 @@ public class AttributeMatcher { * @param attributeName attribute name * @param attributeValue attribute value */ - AttributeMatcher(String attributeName, String attributeValue) { + AttributeMatcher(String attributeName, @Nullable String attributeValue) { this.attributeName = attributeName; this.attributeValue = attributeValue; } @@ -43,24 +43,6 @@ public String getAttributeName() { return attributeName; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof AttributeMatcher)) { - return false; - } - AttributeMatcher other = (AttributeMatcher) o; - return Objects.equals(attributeName, other.attributeName); - } - - @Override - public int hashCode() { - // Do not use value matcher here to support value wildcards - return Objects.hash(attributeName); - } - @Override public String toString() { return attributeValue == null @@ -76,7 +58,7 @@ public String toString() { * @return true if this matcher is matching provided value, false otherwise. */ boolean matchesValue(String value) { - if ((attributeValue == null) || (value == null)) { + if (attributeValue == null) { return true; } return Objects.equals(attributeValue, value); From 7754e3ac2c35530607bcf78e4592609dce8aa6ec Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:24:50 +0100 Subject: [PATCH 41/53] use AttributeMatcherSet for matching --- .../assertions/DataPointAttributes.java | 15 ++----- .../jmxscraper/assertions/MetricAssert.java | 39 ++++++++++++++----- .../CassandraIntegrationTest.java | 5 +-- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java index ba8d7d016..2feb76b47 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java @@ -6,8 +6,6 @@ package io.opentelemetry.contrib.jmxscraper.assertions; import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; /** * Utility class implementing convenience static methods to construct data point attribute matchers @@ -46,15 +44,10 @@ public static AttributeMatcher attributeWithAnyValue(String name) { * @return set of unique attribute matchers * @throws IllegalArgumentException if provided list contains two or more matchers with the same * name. - * @see MetricAssert#hasDataPointsWithAttributes(Set[]) for detailed description of the algorithm - * used for matching + * @see MetricAssert#hasDataPointsWithAttributes(AttributeMatcherSet...) for detailed description + * off the algorithm used for matching */ - public static Set attributeSet(AttributeMatcher... attributes) { - Set matcherSet = Arrays.stream(attributes).collect(Collectors.toSet()); - if (matcherSet.size() < attributes.length) { - throw new IllegalArgumentException( - "Duplicated matchers found in " + Arrays.toString(attributes)); - } - return matcherSet; + public static AttributeMatcherSet attributeSet(AttributeMatcher... attributes) { + return new AttributeMatcherSet(Arrays.asList(attributes)); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 94a53444f..b3e200393 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -254,11 +254,9 @@ public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expecte * @param attributeMatchers array of attribute matcher sets * @return this */ - @SafeVarargs @CanIgnoreReturnValue @SuppressWarnings("varargs") // required to avoid warning - public final MetricAssert hasDataPointsWithAttributes( - Set... attributeMatchers) { + public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... attributeMatchers) { return checkDataPoints( dataPoints -> { dataPointsCommonCheck(dataPoints); @@ -293,16 +291,37 @@ public final MetricAssert hasDataPointsWithAttributes( } private static boolean matchAttributes( - Set attributeMatchers, Map dataPointAttributes) { - if (attributeMatchers.size() != dataPointAttributes.size()) { - return false; - } - for (AttributeMatcher matcher : attributeMatchers) { - String attributeValue = dataPointAttributes.get(matcher.getAttributeName()); - if (!matcher.matchesValue(attributeValue)) { + AttributeMatcherSet attributeMatcherSet, Map dataPointAttributes) { + + Map matchers = attributeMatcherSet.getMatchers(); + + Set toMatch = new HashSet<>(dataPointAttributes.keySet()); + Set matched = new HashSet<>(); + for (Map.Entry entry : dataPointAttributes.entrySet()) { + AttributeMatcher matcher = matchers.get(entry.getKey()); + if (matcher == null) { + // no matcher for this key: unexpected key + return false; + } + + String value = entry.getValue(); + if (!matcher.matchesValue(value)) { + // value does not match: unexpected value return false; } + toMatch.remove(entry.getKey()); + matched.add(entry.getKey()); } + + if (!toMatch.isEmpty()) { + // unexpected entries in attributes + return false; + } + if (!matched.containsAll(matchers.keySet())) { + // some matchers were not match + return false; + } + return true; } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java index e72c904ee..a9a55ad9d 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java @@ -9,10 +9,9 @@ import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; -import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcher; +import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcherSet; import java.nio.file.Path; import java.time.Duration; -import java.util.Set; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; @@ -184,7 +183,7 @@ protected MetricsVerifier createMetricsVerifier() { errorCountAttributes("Write", "Unavailable"))); } - private static Set errorCountAttributes(String operation, String status) { + private static AttributeMatcherSet errorCountAttributes(String operation, String status) { return attributeSet(attribute("operation", operation), attribute("status", status)); } } From 7b7f0d08c9fd50e3f3940c92a00053d294839572 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:33:41 +0100 Subject: [PATCH 42/53] code cleanup --- .../contrib/jmxscraper/assertions/MetricAssert.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index b3e200393..bd8e6d790 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -255,7 +255,6 @@ public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expecte * @return this */ @CanIgnoreReturnValue - @SuppressWarnings("varargs") // required to avoid warning public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... attributeMatchers) { return checkDataPoints( dataPoints -> { @@ -318,7 +317,7 @@ private static boolean matchAttributes( return false; } if (!matched.containsAll(matchers.keySet())) { - // some matchers were not match + // some matchers were not matched return false; } From b170021665d28702e734d549173d497d209940b7 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:02:54 +0100 Subject: [PATCH 43/53] move set matching --- .../assertions/AttributeMatcherSet.java | 27 ++++++++++++++ .../jmxscraper/assertions/MetricAssert.java | 37 +------------------ 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java index 2c884681b..649262c0b 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java @@ -30,6 +30,33 @@ Map getMatchers() { return matchers; } + /** + * Checks if attributes match this attribute matcher set + * + * @param attributes attributes to check as map + * @return {@literal true} when the attributes match all attributes from this set + */ + public boolean matches(Map attributes) { + if(attributes.size() != matchers.size()) { + return false; + } + + for (Map.Entry entry : attributes.entrySet()) { + AttributeMatcher matcher = matchers.get(entry.getKey()); + if (matcher == null) { + // no matcher for this key: unexpected key + return false; + } + + if (!matcher.matchesValue(entry.getValue())) { + // value does not match: unexpected value + return false; + } + } + + return true; + } + @Override public String toString() { return matchers.values().toString(); diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index bd8e6d790..4dbdc7a33 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -267,7 +267,7 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att Map dataPointAttributes = toMap(dataPoint.getAttributesList()); int matchCount = 0; for (int i = 0; i < attributeMatchers.length; i++) { - if (matchAttributes(attributeMatchers[i], dataPointAttributes)) { + if (attributeMatchers[i].matches(dataPointAttributes)) { matchedSets[i] = true; matchCount++; } @@ -289,41 +289,6 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att }); } - private static boolean matchAttributes( - AttributeMatcherSet attributeMatcherSet, Map dataPointAttributes) { - - Map matchers = attributeMatcherSet.getMatchers(); - - Set toMatch = new HashSet<>(dataPointAttributes.keySet()); - Set matched = new HashSet<>(); - for (Map.Entry entry : dataPointAttributes.entrySet()) { - AttributeMatcher matcher = matchers.get(entry.getKey()); - if (matcher == null) { - // no matcher for this key: unexpected key - return false; - } - - String value = entry.getValue(); - if (!matcher.matchesValue(value)) { - // value does not match: unexpected value - return false; - } - toMatch.remove(entry.getKey()); - matched.add(entry.getKey()); - } - - if (!toMatch.isEmpty()) { - // unexpected entries in attributes - return false; - } - if (!matched.containsAll(matchers.keySet())) { - // some matchers were not matched - return false; - } - - return true; - } - private static Map toMap(List list) { return list.stream() .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); From 59a7dfc951e5f9cd24cf635db48b97789c6589d4 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:03:23 +0100 Subject: [PATCH 44/53] inline conversion to map --- .../contrib/jmxscraper/assertions/MetricAssert.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 4dbdc7a33..3137ce7d8 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -264,7 +264,8 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att // validate each datapoint attributes match exactly one of the provided attributes sets for (NumberDataPoint dataPoint : dataPoints) { - Map dataPointAttributes = toMap(dataPoint.getAttributesList()); + Map dataPointAttributes = dataPoint.getAttributesList().stream() + .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); int matchCount = 0; for (int i = 0; i < attributeMatchers.length; i++) { if (attributeMatchers[i].matches(dataPointAttributes)) { @@ -289,8 +290,4 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att }); } - private static Map toMap(List list) { - return list.stream() - .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); - } } From 34b3ab30d59d40627c5e986467cbef5ac242c780 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:06:38 +0100 Subject: [PATCH 45/53] reformat & cleanup --- .../contrib/jmxscraper/assertions/AttributeMatcherSet.java | 6 +----- .../contrib/jmxscraper/assertions/MetricAssert.java | 7 ++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java index 649262c0b..9fab0c56e 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java @@ -26,10 +26,6 @@ public class AttributeMatcherSet { matchers.stream().collect(Collectors.toMap(AttributeMatcher::getAttributeName, m -> m)); } - Map getMatchers() { - return matchers; - } - /** * Checks if attributes match this attribute matcher set * @@ -37,7 +33,7 @@ Map getMatchers() { * @return {@literal true} when the attributes match all attributes from this set */ public boolean matches(Map attributes) { - if(attributes.size() != matchers.size()) { + if (attributes.size() != matchers.size()) { return false; } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 3137ce7d8..6c712c671 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -264,8 +264,10 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att // validate each datapoint attributes match exactly one of the provided attributes sets for (NumberDataPoint dataPoint : dataPoints) { - Map dataPointAttributes = dataPoint.getAttributesList().stream() - .collect(Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); + Map dataPointAttributes = + dataPoint.getAttributesList().stream() + .collect( + Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); int matchCount = 0; for (int i = 0; i < attributeMatchers.length; i++) { if (attributeMatchers[i].matches(dataPointAttributes)) { @@ -289,5 +291,4 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att } }); } - } From 45ba126f3c2c78f8c643c610f0a9bc6488348158 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:54:45 +0100 Subject: [PATCH 46/53] simplify matchesValue --- .../contrib/jmxscraper/assertions/AttributeMatcher.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index 097f74a48..04aaff092 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -57,9 +57,6 @@ public String toString() { * @return true if this matcher is matching provided value, false otherwise. */ boolean matchesValue(String value) { - if (attributeValue == null) { - return true; - } - return Objects.equals(attributeValue, value); + return attributeValue == null || attributeValue.equals(value); } } From 5e69a82d2ef3e7532fe9f34548b6c36550ab6393 Mon Sep 17 00:00:00 2001 From: Sylvain Juge <763082+SylvainJuge@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:00:45 +0100 Subject: [PATCH 47/53] rename attribute set -> group --- .../assertions/AttributeMatcher.java | 1 - ...herSet.java => AttributeMatcherGroup.java} | 12 +++--- .../assertions/DataPointAttributes.java | 16 ++++---- .../jmxscraper/assertions/MetricAssert.java | 28 +++++++------- .../ActiveMqIntegrationTest.java | 18 ++++----- .../CassandraIntegrationTest.java | 14 +++---- .../target_systems/HBaseIntegrationTest.java | 38 +++++++++---------- .../target_systems/JettyIntegrationTest.java | 8 ++-- 8 files changed, 67 insertions(+), 68 deletions(-) rename jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/{AttributeMatcherSet.java => AttributeMatcherGroup.java} (82%) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java index 04aaff092..491756311 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcher.java @@ -5,7 +5,6 @@ package io.opentelemetry.contrib.jmxscraper.assertions; -import java.util.Objects; import javax.annotation.Nullable; /** Implements functionality of matching data point attributes. */ diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherGroup.java similarity index 82% rename from jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java rename to jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherGroup.java index 9fab0c56e..df87d739d 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherSet.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/AttributeMatcherGroup.java @@ -9,8 +9,8 @@ import java.util.Map; import java.util.stream.Collectors; -/** Holder class for a set of attribute matchers */ -public class AttributeMatcherSet { +/** Group of attribute matchers */ +public class AttributeMatcherGroup { // stored as a Map for easy lookup by name private final Map matchers; @@ -18,19 +18,19 @@ public class AttributeMatcherSet { /** * Constructor for a set of attribute matchers * - * @param matchers collection of matchers to build a set from + * @param matchers collection of matchers to build a group from * @throws IllegalStateException if there is any duplicate key */ - AttributeMatcherSet(Collection matchers) { + AttributeMatcherGroup(Collection matchers) { this.matchers = matchers.stream().collect(Collectors.toMap(AttributeMatcher::getAttributeName, m -> m)); } /** - * Checks if attributes match this attribute matcher set + * Checks if attributes match this attribute matcher group * * @param attributes attributes to check as map - * @return {@literal true} when the attributes match all attributes from this set + * @return {@literal true} when the attributes match all attributes from this group */ public boolean matches(Map attributes) { if (attributes.size() != matchers.size()) { diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java index 2feb76b47..4545c4f34 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/DataPointAttributes.java @@ -38,16 +38,16 @@ public static AttributeMatcher attributeWithAnyValue(String name) { } /** - * Create a set of attribute matchers that should be used to verify set of data point attributes. + * Creates a group of attribute matchers that should be used to verify data point attributes. * - * @param attributes list of matchers to create set. It must contain matchers with unique names. - * @return set of unique attribute matchers + * @param attributes list of matchers to create group. It must contain matchers with unique names. + * @return group of attribute matchers * @throws IllegalArgumentException if provided list contains two or more matchers with the same - * name. - * @see MetricAssert#hasDataPointsWithAttributes(AttributeMatcherSet...) for detailed description - * off the algorithm used for matching + * attribute name + * @see MetricAssert#hasDataPointsWithAttributes(AttributeMatcherGroup...) for detailed + * description off the algorithm used for matching */ - public static AttributeMatcherSet attributeSet(AttributeMatcher... attributes) { - return new AttributeMatcherSet(Arrays.asList(attributes)); + public static AttributeMatcherGroup attributeGroup(AttributeMatcher... attributes) { + return new AttributeMatcherGroup(Arrays.asList(attributes)); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java index 6c712c671..1a4eaace3 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/assertions/MetricAssert.java @@ -5,7 +5,7 @@ package io.opentelemetry.contrib.jmxscraper.assertions; -import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.proto.common.v1.KeyValue; @@ -241,26 +241,26 @@ private void dataPointsCommonCheck(List dataPoints) { */ @CanIgnoreReturnValue public final MetricAssert hasDataPointsWithOneAttribute(AttributeMatcher expectedAttribute) { - return hasDataPointsWithAttributes(attributeSet(expectedAttribute)); + return hasDataPointsWithAttributes(attributeGroup(expectedAttribute)); } /** - * Verifies that every data point attributes set is matched exactly by one of the matcher sets - * provided. Also, each matcher set must match at least one data point attributes set. Data point - * attributes set is matched by matcher set if each attribute is matched by one matcher and each - * matcher matches one attribute. In other words: number of attributes is the same as number of - * matchers and there is 1:1 matching between them. + * Verifies that every data point attributes is matched exactly by one of the matcher groups + * provided. Also, each matcher group must match at least one data point attributes set. Data + * point attributes are matched by matcher group if each attribute is matched by one matcher and + * each matcher matches one attribute. In other words: number of attributes is the same as number + * of matchers and there is 1:1 matching between them. * - * @param attributeMatchers array of attribute matcher sets + * @param matcherGroups array of attribute matcher groups * @return this */ @CanIgnoreReturnValue - public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... attributeMatchers) { + public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherGroup... matcherGroups) { return checkDataPoints( dataPoints -> { dataPointsCommonCheck(dataPoints); - boolean[] matchedSets = new boolean[attributeMatchers.length]; + boolean[] matchedSets = new boolean[matcherGroups.length]; // validate each datapoint attributes match exactly one of the provided attributes sets for (NumberDataPoint dataPoint : dataPoints) { @@ -269,8 +269,8 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att .collect( Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); int matchCount = 0; - for (int i = 0; i < attributeMatchers.length; i++) { - if (attributeMatchers[i].matches(dataPointAttributes)) { + for (int i = 0; i < matcherGroups.length; i++) { + if (matcherGroups[i].matches(dataPointAttributes)) { matchedSets[i] = true; matchCount++; } @@ -278,7 +278,7 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att info.description( "data point attributes '%s' for metric '%s' must match exactly one of the attribute sets '%s'", - dataPointAttributes, actual.getName(), Arrays.asList(attributeMatchers)); + dataPointAttributes, actual.getName(), Arrays.asList(matcherGroups)); integers.assertEqual(info, matchCount, 1); } @@ -286,7 +286,7 @@ public final MetricAssert hasDataPointsWithAttributes(AttributeMatcherSet... att for (int i = 0; i < matchedSets.length; i++) { info.description( "no data point matched attribute set '%s' for metric '%s'", - attributeMatchers[i], actual.getName()); + matcherGroups[i], actual.getName()); objects.assertEqual(info, matchedSets[i], true); } }); diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java index dc35d4af5..4f909fdc5 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/ActiveMqIntegrationTest.java @@ -6,7 +6,7 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; -import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import java.nio.file.Path; @@ -48,7 +48,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("{consumer}") .isUpDownCounter() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -59,7 +59,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("{producer}") .isUpDownCounter() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -78,7 +78,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("%") .isGauge() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -107,7 +107,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("{message}") .isUpDownCounter() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -119,7 +119,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("{message}") .isCounter() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -130,7 +130,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("{message}") .isCounter() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -141,7 +141,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("{message}") .isCounter() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))) .add( @@ -152,7 +152,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("ms") .isGauge() .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("destination", "ActiveMQ.Advisory.MasterBroker"), attribute("broker", "localhost")))); } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java index a9a55ad9d..7730f34a7 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/CassandraIntegrationTest.java @@ -6,10 +6,10 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; -import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; -import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcherSet; +import io.opentelemetry.contrib.jmxscraper.assertions.AttributeMatcherGroup; import java.nio.file.Path; import java.time.Duration; import org.testcontainers.containers.GenericContainer; @@ -161,9 +161,9 @@ protected MetricsVerifier createMetricsVerifier() { .hasUnit("1") .isCounter() .hasDataPointsWithAttributes( - attributeSet(attribute("operation", "RangeSlice")), - attributeSet(attribute("operation", "Read")), - attributeSet(attribute("operation", "Write")))) + attributeGroup(attribute("operation", "RangeSlice")), + attributeGroup(attribute("operation", "Read")), + attributeGroup(attribute("operation", "Write")))) .add( "cassandra.client.request.error.count", metric -> @@ -183,7 +183,7 @@ protected MetricsVerifier createMetricsVerifier() { errorCountAttributes("Write", "Unavailable"))); } - private static AttributeMatcherSet errorCountAttributes(String operation, String status) { - return attributeSet(attribute("operation", operation), attribute("status", status)); + private static AttributeMatcherGroup errorCountAttributes(String operation, String status) { + return attributeGroup(attribute("operation", operation), attribute("status", status)); } } diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java index bece18c33..7aee15654 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/HBaseIntegrationTest.java @@ -6,7 +6,7 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; -import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup; import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; @@ -44,8 +44,8 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of region servers.") .hasUnit("{server}") .hasDataPointsWithAttributes( - attributeSet(attribute("state", "dead")), - attributeSet(attribute("state", "live")))) + attributeGroup(attribute("state", "dead")), + attributeGroup(attribute("state", "live")))) .add( "hbase.master.regions_in_transition.count", metric -> @@ -128,9 +128,9 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of requests received.") .hasUnit("{request}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("state", "write"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("state", "read"), attributeWithAnyValue("region_server")))) .add( "hbase.region_server.queue.length", @@ -140,9 +140,9 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of RPC handlers actively servicing requests.") .hasUnit("{handler}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("state", "flush"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("state", "compaction"), attributeWithAnyValue("region_server")))) .add( @@ -162,9 +162,9 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("Number of block cache hits/misses.") .hasUnit("{operation}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("state", "miss"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("state", "hit"), attributeWithAnyValue("region_server")))) .add( "hbase.region_server.files.local", @@ -436,17 +436,17 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("Number of operations that took over 1000ms to complete.") .hasUnit("{operation}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("operation", "delete"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("operation", "append"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("operation", "get"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("operation", "put"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("operation", "increment"), attributeWithAnyValue("region_server")))) .add( @@ -473,12 +473,12 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of currently enqueued requests.") .hasUnit("{request}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("state", "replication"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("state", "user"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("state", "priority"), attributeWithAnyValue("region_server")))) .add( @@ -490,10 +490,10 @@ protected MetricsVerifier createMetricsVerifier() { "Number of client connection authentication failures/successes.") .hasUnit("{authentication request}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attribute("state", "successes"), attributeWithAnyValue("region_server")), - attributeSet( + attributeGroup( attribute("state", "failures"), attributeWithAnyValue("region_server")))) .add( diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java index ed44316b9..86097cbaa 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/JettyIntegrationTest.java @@ -6,7 +6,7 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; -import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeSet; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup; import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; @@ -88,7 +88,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The number of select calls.") .hasUnit("{operation}") .hasDataPointsWithAttributes( - attributeSet( + attributeGroup( attributeWithAnyValue("context"), attributeWithAnyValue("id")))) .add( "jetty.thread.count", @@ -98,8 +98,8 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The current number of threads.") .hasUnit("{thread}") .hasDataPointsWithAttributes( - attributeSet(attribute("state", "busy")), - attributeSet(attribute("state", "idle")))) + attributeGroup(attribute("state", "busy")), + attributeGroup(attribute("state", "idle")))) .add( "jetty.thread.queue.count", metric -> From 036ea99eb970180743afc0ec56e13360af54cc38 Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 10 Dec 2024 13:01:14 +0100 Subject: [PATCH 48/53] Use new metrics assertions framework --- .../target_systems/TomcatIntegrationTest.java | 142 ++++++++++-------- 1 file changed, 77 insertions(+), 65 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java index 66fb3ec86..80ccde799 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java @@ -5,9 +5,9 @@ package io.opentelemetry.contrib.jmxscraper.target_systems; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertGaugeWithAttributes; -import static io.opentelemetry.contrib.jmxscraper.target_systems.MetricAssertions.assertSumWithAttributes; -import static org.assertj.core.api.Assertions.entry; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attribute; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeGroup; +import static io.opentelemetry.contrib.jmxscraper.assertions.DataPointAttributes.attributeWithAnyValue; import io.opentelemetry.contrib.jmxscraper.JmxScraperContainer; import java.nio.file.Path; @@ -46,67 +46,79 @@ protected JmxScraperContainer customizeScraperContainer( } @Override - protected void verifyMetrics() { - waitAndAssertMetrics( - metric -> - assertGaugeWithAttributes( - metric, - "tomcat.sessions", - "The number of active sessions", - "sessions", - attrs -> attrs.containsKey("context")), - metric -> - assertSumWithAttributes( - metric, - "tomcat.errors", - "The number of errors encountered", - "errors", - attrs -> attrs.containsOnly(entry("proto_handler", "\"http-nio-8080\""))), - metric -> - assertSumWithAttributes( - metric, - "tomcat.processing_time", - "The total processing time", - "ms", - attrs -> attrs.containsOnly(entry("proto_handler", "\"http-nio-8080\""))), - metric -> - assertSumWithAttributes( - metric, - "tomcat.traffic", - "The number of bytes transmitted and received", - "by", - attrs -> - attrs.containsOnly( - entry("proto_handler", "\"http-nio-8080\""), entry("direction", "sent")), - attrs -> - attrs.containsOnly( - entry("proto_handler", "\"http-nio-8080\""), - entry("direction", "received"))), - metric -> - assertGaugeWithAttributes( - metric, - "tomcat.threads", - "The number of threads", - "threads", - attrs -> - attrs.containsOnly( - entry("proto_handler", "\"http-nio-8080\""), entry("state", "idle")), - attrs -> - attrs.containsOnly( - entry("proto_handler", "\"http-nio-8080\""), entry("state", "busy"))), - metric -> - assertGaugeWithAttributes( - metric, - "tomcat.max_time", - "Maximum time to process a request", - "ms", - attrs -> attrs.containsOnly(entry("proto_handler", "\"http-nio-8080\""))), - metric -> - assertSumWithAttributes( - metric, - "tomcat.request_count", - "The total requests", - "requests", - attrs -> attrs.containsOnly(entry("proto_handler", "\"http-nio-8080\"")))); + protected MetricsVerifier createMetricsVerifier() { + return MetricsVerifier.create() + .add( + "tomcat.sessions", + metric -> + metric + .hasDescription("The number of active sessions") + .hasUnit("sessions") // TODO: not aligned with semconv. Should be "{session}" + .isGauge() + .hasDataPointsWithOneAttribute(attributeWithAnyValue("context"))) + .add( + "tomcat.errors", + metric -> + metric + .hasDescription("The number of errors encountered") + .hasUnit("errors") // TODO: not aligned with semconv. Should be "{error}" + .isCounter() + .hasDataPointsWithOneAttribute(attribute("proto_handler", "\"http-nio-8080\""))) + .add( + "tomcat.processing_time", + metric -> + metric + .hasDescription("The total processing time") + .hasUnit("ms") + .isCounter() + .hasDataPointsWithOneAttribute(attribute("proto_handler", "\"http-nio-8080\""))) + .add( + "tomcat.traffic", + metric -> + metric + .hasDescription("The number of bytes transmitted and received") + .hasUnit("by") + .isCounter() + .hasDataPointsWithAttributes( + attributeGroup( + attribute("direction", "sent"), + attribute("proto_handler", "\"http-nio-8080\"")), + attributeGroup( + attribute("direction", "received"), + attribute("proto_handler", "\"http-nio-8080\"")) + + )) + .add( + "tomcat.threads", + metric -> + metric + .hasDescription("The number of threads") + .hasUnit("threads") // TODO: not aligned with semconv. Should be "{thread}" + .isGauge() + .hasDataPointsWithAttributes( + attributeGroup( + attribute("state", "idle"), + attribute("proto_handler", "\"http-nio-8080\"")), + attributeGroup( + attribute("state", "busy"), + attribute("proto_handler", "\"http-nio-8080\"")) + + )) + .add( + "tomcat.max_time", + metric -> + metric + .hasDescription("Maximum time to process a request") + .hasUnit("ms") + .isGauge() + .hasDataPointsWithOneAttribute(attribute("proto_handler", "\"http-nio-8080\""))) + .add( + "tomcat.request_count", + metric -> + metric + .hasDescription("The total requests") + .hasUnit("requests") // TODO: not aligned with semconv. Should be "{request}" + .isCounter() + .hasDataPointsWithOneAttribute(attribute("proto_handler", "\"http-nio-8080\""))); } } From 687002ce9282cd5940812eb5715160a757497dcd Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 10 Dec 2024 13:02:46 +0100 Subject: [PATCH 49/53] Spotless fix --- .../target_systems/TomcatIntegrationTest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java index 80ccde799..766b08ae2 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java @@ -85,9 +85,7 @@ protected MetricsVerifier createMetricsVerifier() { attribute("proto_handler", "\"http-nio-8080\"")), attributeGroup( attribute("direction", "received"), - attribute("proto_handler", "\"http-nio-8080\"")) - - )) + attribute("proto_handler", "\"http-nio-8080\"")))) .add( "tomcat.threads", metric -> @@ -101,9 +99,7 @@ protected MetricsVerifier createMetricsVerifier() { attribute("proto_handler", "\"http-nio-8080\"")), attributeGroup( attribute("state", "busy"), - attribute("proto_handler", "\"http-nio-8080\"")) - - )) + attribute("proto_handler", "\"http-nio-8080\"")))) .add( "tomcat.max_time", metric -> @@ -119,6 +115,7 @@ protected MetricsVerifier createMetricsVerifier() { .hasDescription("The total requests") .hasUnit("requests") // TODO: not aligned with semconv. Should be "{request}" .isCounter() - .hasDataPointsWithOneAttribute(attribute("proto_handler", "\"http-nio-8080\""))); + .hasDataPointsWithOneAttribute( + attribute("proto_handler", "\"http-nio-8080\""))); } } From cf0a17ae538803eed34639d10bec447f219ab330 Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 10 Dec 2024 14:17:17 +0100 Subject: [PATCH 50/53] Added comment about unit not aligned with semconv --- .../jmxscraper/target_systems/TomcatIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java index 766b08ae2..2f890ff1b 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java @@ -77,7 +77,7 @@ protected MetricsVerifier createMetricsVerifier() { metric -> metric .hasDescription("The number of bytes transmitted and received") - .hasUnit("by") + .hasUnit("by") // TODO: not aligned with semconv. Should be "By" .isCounter() .hasDataPointsWithAttributes( attributeGroup( From ebedd5f2474186ae9256a8d7f9d37e502bf45630 Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 11 Dec 2024 09:31:22 +0100 Subject: [PATCH 51/53] Units updated to align with semconv --- .../target_systems/TomcatIntegrationTest.java | 10 +++++----- jmx-scraper/src/main/resources/tomcat.yaml | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java index 2f890ff1b..bec9453f8 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/TomcatIntegrationTest.java @@ -53,7 +53,7 @@ protected MetricsVerifier createMetricsVerifier() { metric -> metric .hasDescription("The number of active sessions") - .hasUnit("sessions") // TODO: not aligned with semconv. Should be "{session}" + .hasUnit("{session}") .isGauge() .hasDataPointsWithOneAttribute(attributeWithAnyValue("context"))) .add( @@ -61,7 +61,7 @@ protected MetricsVerifier createMetricsVerifier() { metric -> metric .hasDescription("The number of errors encountered") - .hasUnit("errors") // TODO: not aligned with semconv. Should be "{error}" + .hasUnit("{error}") .isCounter() .hasDataPointsWithOneAttribute(attribute("proto_handler", "\"http-nio-8080\""))) .add( @@ -77,7 +77,7 @@ protected MetricsVerifier createMetricsVerifier() { metric -> metric .hasDescription("The number of bytes transmitted and received") - .hasUnit("by") // TODO: not aligned with semconv. Should be "By" + .hasUnit("By") .isCounter() .hasDataPointsWithAttributes( attributeGroup( @@ -91,7 +91,7 @@ protected MetricsVerifier createMetricsVerifier() { metric -> metric .hasDescription("The number of threads") - .hasUnit("threads") // TODO: not aligned with semconv. Should be "{thread}" + .hasUnit("{thread}") .isGauge() .hasDataPointsWithAttributes( attributeGroup( @@ -113,7 +113,7 @@ protected MetricsVerifier createMetricsVerifier() { metric -> metric .hasDescription("The total requests") - .hasUnit("requests") // TODO: not aligned with semconv. Should be "{request}" + .hasUnit("{request}") .isCounter() .hasDataPointsWithOneAttribute( attribute("proto_handler", "\"http-nio-8080\""))); diff --git a/jmx-scraper/src/main/resources/tomcat.yaml b/jmx-scraper/src/main/resources/tomcat.yaml index 076be6400..ad67ce8b8 100644 --- a/jmx-scraper/src/main/resources/tomcat.yaml +++ b/jmx-scraper/src/main/resources/tomcat.yaml @@ -15,7 +15,7 @@ rules: activeSessions: metric: tomcat.sessions type: gauge - unit: sessions + unit: "{session}" desc: The number of active sessions - beans: @@ -28,12 +28,12 @@ rules: errorCount: metric: errors type: counter - unit: errors + unit: "{error}" desc: The number of errors encountered requestCount: metric: request_count type: counter - unit: requests + unit: "{request}" desc: The total requests maxTime: metric: max_time @@ -48,14 +48,14 @@ rules: bytesSent: metric: traffic type: counter - unit: by + unit: By desc: The number of bytes transmitted and received metricAttribute: direction: const(sent) bytesReceived: metric: traffic type: counter - unit: by + unit: By desc: The number of bytes transmitted and received metricAttribute: direction: const(received) @@ -71,13 +71,13 @@ rules: metric: threads desc: The number of threads type: gauge - unit: threads + unit: "{thread}" metricAttribute: state: const(idle) currentThreadsBusy: metric: threads desc: The number of threads type: gauge - unit: threads + unit: "{thread}" metricAttribute: state: const(busy) From d286b7a80b57b7232b87e66566955924b4286d2d Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 11 Dec 2024 10:46:35 +0100 Subject: [PATCH 52/53] Update JMX Metrics Gatherer units definitions for Cassandra to match semconv --- .../target_systems/TomcatIntegrationTest.java | 10 +++++----- .../resources/target-systems/tomcat.groovy | 20 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/jmx-metrics/src/integrationTest/java/io/opentelemetry/contrib/jmxmetrics/target_systems/TomcatIntegrationTest.java b/jmx-metrics/src/integrationTest/java/io/opentelemetry/contrib/jmxmetrics/target_systems/TomcatIntegrationTest.java index ad42c1927..5aa08f2c0 100644 --- a/jmx-metrics/src/integrationTest/java/io/opentelemetry/contrib/jmxmetrics/target_systems/TomcatIntegrationTest.java +++ b/jmx-metrics/src/integrationTest/java/io/opentelemetry/contrib/jmxmetrics/target_systems/TomcatIntegrationTest.java @@ -53,13 +53,13 @@ class TomcatIntegrationTest extends AbstractIntegrationTest { void endToEnd() { waitAndAssertMetrics( metric -> - assertGauge(metric, "tomcat.sessions", "The number of active sessions.", "sessions"), + assertGauge(metric, "tomcat.sessions", "The number of active sessions.", "{session}"), metric -> assertSumWithAttributes( metric, "tomcat.errors", "The number of errors encountered.", - "errors", + "{error}", attrs -> attrs.containsOnly(entry("proto_handler", "\"http-nio-8080\""))), metric -> assertSumWithAttributes( @@ -73,7 +73,7 @@ void endToEnd() { metric, "tomcat.traffic", "The number of bytes transmitted and received.", - "by", + "By", attrs -> attrs.containsOnly( entry("proto_handler", "\"http-nio-8080\""), entry("direction", "sent")), @@ -86,7 +86,7 @@ void endToEnd() { metric, "tomcat.threads", "The number of threads", - "threads", + "{thread}", attrs -> attrs.containsOnly( entry("proto_handler", "\"http-nio-8080\""), entry("state", "idle")), @@ -105,7 +105,7 @@ void endToEnd() { metric, "tomcat.request_count", "The total requests.", - "requests", + "{request}", attrs -> attrs.containsOnly(entry("proto_handler", "\"http-nio-8080\"")))); } } diff --git a/jmx-metrics/src/main/resources/target-systems/tomcat.groovy b/jmx-metrics/src/main/resources/target-systems/tomcat.groovy index 8c692befc..32fe2246d 100644 --- a/jmx-metrics/src/main/resources/target-systems/tomcat.groovy +++ b/jmx-metrics/src/main/resources/target-systems/tomcat.groovy @@ -16,13 +16,13 @@ def beantomcatmanager = otel.mbeans("Catalina:type=Manager,host=localhost,context=*") -otel.instrument(beantomcatmanager, "tomcat.sessions", "The number of active sessions.", "sessions", "activeSessions", otel.&longValueCallback) +otel.instrument(beantomcatmanager, "tomcat.sessions", "The number of active sessions.", "{session}", "activeSessions", otel.&longValueCallback) def beantomcatrequestProcessor = otel.mbeans("Catalina:type=GlobalRequestProcessor,name=*") -otel.instrument(beantomcatrequestProcessor, "tomcat.errors", "The number of errors encountered.", "errors", +otel.instrument(beantomcatrequestProcessor, "tomcat.errors", "The number of errors encountered.", "{error}", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], "errorCount", otel.&longCounterCallback) -otel.instrument(beantomcatrequestProcessor, "tomcat.request_count", "The total requests.", "requests", +otel.instrument(beantomcatrequestProcessor, "tomcat.request_count", "The total requests.", "{request}", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], "requestCount", otel.&longCounterCallback) otel.instrument(beantomcatrequestProcessor, "tomcat.max_time", "Maximum time to process a request.", "ms", @@ -32,24 +32,24 @@ otel.instrument(beantomcatrequestProcessor, "tomcat.processing_time", "The total ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], "processingTime", otel.&longCounterCallback) otel.instrument(beantomcatrequestProcessor, "tomcat.traffic", - "The number of bytes transmitted and received.", "by", + "The number of bytes transmitted and received.", "By", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name")}], ["bytesReceived":["direction" : {"received"}], "bytesSent": ["direction" : {"sent"}]], otel.&longCounterCallback) def beantomcatconnectors = otel.mbeans("Catalina:type=ThreadPool,name=*") -otel.instrument(beantomcatconnectors, "tomcat.threads", "The number of threads", "threads", +otel.instrument(beantomcatconnectors, "tomcat.threads", "The number of threads", "{thread}", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], ["currentThreadCount":["state":{"idle"}],"currentThreadsBusy":["state":{"busy"}]], otel.&longValueCallback) def beantomcatnewmanager = otel.mbeans("Tomcat:type=Manager,host=localhost,context=*") -otel.instrument(beantomcatnewmanager, "tomcat.sessions", "The number of active sessions.", "sessions", "activeSessions", otel.&longValueCallback) +otel.instrument(beantomcatnewmanager, "tomcat.sessions", "The number of active sessions.", "{session}", "activeSessions", otel.&longValueCallback) def beantomcatnewrequestProcessor = otel.mbeans("Tomcat:type=GlobalRequestProcessor,name=*") -otel.instrument(beantomcatnewrequestProcessor, "tomcat.errors", "The number of errors encountered.", "errors", +otel.instrument(beantomcatnewrequestProcessor, "tomcat.errors", "The number of errors encountered.", "{error}", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], "errorCount", otel.&longCounterCallback) -otel.instrument(beantomcatnewrequestProcessor, "tomcat.request_count", "The total requests.", "requests", +otel.instrument(beantomcatnewrequestProcessor, "tomcat.request_count", "The total requests.", "{request}", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], "requestCount", otel.&longCounterCallback) otel.instrument(beantomcatnewrequestProcessor, "tomcat.max_time", "Maximum time to process a request.", "ms", @@ -59,12 +59,12 @@ otel.instrument(beantomcatnewrequestProcessor, "tomcat.processing_time", "The to ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], "processingTime", otel.&longCounterCallback) otel.instrument(beantomcatnewrequestProcessor, "tomcat.traffic", - "The number of bytes transmitted and received.", "by", + "The number of bytes transmitted and received.", "By", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name")}], ["bytesReceived":["direction" : {"received"}], "bytesSent": ["direction" : {"sent"}]], otel.&longCounterCallback) def beantomcatnewconnectors = otel.mbeans("Tomcat:type=ThreadPool,name=*") -otel.instrument(beantomcatnewconnectors, "tomcat.threads", "The number of threads", "threads", +otel.instrument(beantomcatnewconnectors, "tomcat.threads", "The number of threads", "{thread}", ["proto_handler" : { mbean -> mbean.name().getKeyProperty("name") }], ["currentThreadCount":["state":{"idle"}],"currentThreadsBusy":["state":{"busy"}]], otel.&longValueCallback) From 014d7c9b72762a192790a68eec5c7b7775d55d98 Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 11 Dec 2024 13:38:38 +0100 Subject: [PATCH 53/53] Unused methods removed --- .../target_systems/MetricAssertions.java | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java index 3cc4e8d50..826fe4729 100644 --- a/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java +++ b/jmx-scraper/src/integrationTest/java/io/opentelemetry/contrib/jmxscraper/target_systems/MetricAssertions.java @@ -22,15 +22,6 @@ class MetricAssertions { private MetricAssertions() {} - static void assertGauge(Metric metric, String name, String description, String unit) { - assertThat(metric.getName()).isEqualTo(name); - assertThat(metric) - .hasDescription(description) - .hasUnit(unit) - .isGauge() - .hasDataPointsWithoutAttributes(); - } - static void assertSum(Metric metric, String name, String description, String unit) { assertSum(metric, name, description, unit, /* isMonotonic= */ true); } @@ -73,37 +64,6 @@ static void assertSumWithAttributes( assertAttributedPoints(metric.getSum().getDataPointsList(), attributeGroupAssertions); } - @SafeVarargs - static void assertSumWithAttributesMultiplePoints( - Metric metric, - String name, - String description, - String unit, - boolean isMonotonic, - Consumer>... attributeGroupAssertions) { - - assertThat(metric.getName()).isEqualTo(name); - assertThat(metric).hasDescription(description).hasUnit(unit); - - assertThat(metric.hasSum()).isTrue(); - assertThat(metric.getSum().getIsMonotonic()).isEqualTo(isMonotonic); - assertAttributedMultiplePoints(metric.getSum().getDataPointsList(), attributeGroupAssertions); - } - - @SafeVarargs - static void assertGaugeWithAttributes( - Metric metric, - String name, - String description, - String unit, - Consumer>... attributeGroupAssertions) { - assertThat(metric.getName()).isEqualTo(name); - - assertThat(metric).hasDescription(description).hasUnit(unit).isGauge(); - - assertAttributedPoints(metric.getGauge().getDataPointsList(), attributeGroupAssertions); - } - @SuppressWarnings("unchecked") private static void assertAttributedPoints( List points, @@ -122,22 +82,4 @@ private static void assertAttributedPoints( KeyValue::getKey, keyValue -> keyValue.getValue().getStringValue()))) .satisfiesExactlyInAnyOrder(assertions); } - - @SuppressWarnings("unchecked") - private static void assertAttributedMultiplePoints( - List points, - Consumer>... attributeGroupAssertions) { - - points.stream() - .map(NumberDataPoint::getAttributesList) - .forEach( - kvList -> { - Map kvMap = - kvList.stream() - .collect( - Collectors.toMap(KeyValue::getKey, kv -> kv.getValue().getStringValue())); - Arrays.stream(attributeGroupAssertions) - .forEach(assertion -> assertion.accept(assertThat(kvMap))); - }); - } }