diff --git a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServer.java b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServer.java index f828205e774..3e0eafe9670 100644 --- a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServer.java +++ b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServer.java @@ -10,6 +10,8 @@ package io.opentelemetry.exporter.prometheus; +import static java.util.stream.Collectors.joining; + import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; @@ -34,11 +36,14 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.GZIPOutputStream; import javax.annotation.Nullable; @@ -52,6 +57,7 @@ public final class PrometheusHttpServer implements Closeable, MetricReader { private static final DaemonThreadFactory THREAD_FACTORY = new DaemonThreadFactory("prometheus-http"); + private static final Logger LOGGER = Logger.getLogger(PrometheusHttpServer.class.getName()); private final HttpServer server; private final ExecutorService executor; @@ -77,9 +83,10 @@ public static PrometheusHttpServerBuilder builder() { } catch (IOException e) { throw new UncheckedIOException("Could not create Prometheus HTTP server", e); } - server.createContext("/", new MetricsHandler(() -> getMetricProducer().collectAllMetrics())); - server.createContext( - "/metrics", new MetricsHandler(() -> getMetricProducer().collectAllMetrics())); + MetricsHandler metricsHandler = + new MetricsHandler(() -> getMetricProducer().collectAllMetrics()); + server.createContext("/", metricsHandler); + server.createContext("/metrics", metricsHandler); server.createContext("/-/healthy", HealthHandler.INSTANCE); executor = Executors.newFixedThreadPool(5, THREAD_FACTORY); @@ -159,6 +166,9 @@ InetSocketAddress getAddress() { private static class MetricsHandler implements HttpHandler { + private final Set allConflictHeaderNames = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Supplier> metricsSupplier; private MetricsHandler(Supplier> metricsSupplier) { @@ -190,7 +200,15 @@ public void handle(HttpExchange exchange) throws IOException { } else { out = exchange.getResponseBody(); } - serializer.write(metrics, out); + Set conflictHeaderNames = serializer.write(metrics, out); + conflictHeaderNames.removeAll(allConflictHeaderNames); + if (conflictHeaderNames.size() > 0 && LOGGER.isLoggable(Level.WARNING)) { + LOGGER.log( + Level.WARNING, + "Metric conflict(s) detected. Multiple metrics with same name but different type: " + + conflictHeaderNames.stream().collect(joining(",", "[", "]"))); + allConflictHeaderNames.addAll(conflictHeaderNames); + } } exchange.close(); } diff --git a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Serializer.java b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Serializer.java index 78c810f1216..165776b4095 100644 --- a/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Serializer.java +++ b/exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/Serializer.java @@ -46,23 +46,25 @@ import java.io.UncheckedIOException; import java.io.Writer; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Predicate; -import java.util.stream.Collectors; import javax.annotation.Nullable; /** Serializes metrics into Prometheus exposition formats. */ // Adapted from // https://github.com/prometheus/client_java/blob/master/simpleclient_common/src/main/java/io/prometheus/client/exporter/common/TextFormat.java abstract class Serializer { - static Serializer create(@Nullable String acceptHeader, Predicate filter) { if (acceptHeader == null) { return new Prometheus004Serializer(filter); @@ -100,61 +102,64 @@ abstract void writeExemplar( abstract void writeEof(Writer writer) throws IOException; - final void write(Collection metrics, OutputStream output) throws IOException { - Map> metricsByScope = - metrics.stream() - // Not supported in specification yet. - .filter(metric -> metric.getType() != MetricDataType.EXPONENTIAL_HISTOGRAM) - // PrometheusHttpServer#getAggregationTemporality specifies cumulative temporality for - // all instruments, but non-SDK MetricProducers may not conform. We drop delta - // temporality metrics to avoid the complexity of stateful transformation to cumulative. - .filter(metric -> !isDeltaTemporality(metric)) - .filter(metric -> metricNameFilter.test(metricName(metric))) - .collect( - Collectors.groupingBy( - MetricData::getInstrumentationScopeInfo, - LinkedHashMap::new, - Collectors.toList())); + final Set write(Collection metrics, OutputStream output) throws IOException { + Set conflictMetricNames = new HashSet<>(); + Map> metricsByName = new LinkedHashMap<>(); + Set scopes = new LinkedHashSet<>(); + // Iterate through metrics, filtering and grouping by headerName + for (MetricData metric : metrics) { + // Not supported in specification yet. + if (metric.getType() == MetricDataType.EXPONENTIAL_HISTOGRAM) { + continue; + } + // PrometheusHttpServer#getAggregationTemporality specifies cumulative temporality for + // all instruments, but non-SDK MetricProducers may not conform. We drop delta + // temporality metrics to avoid the complexity of stateful transformation to cumulative. + if (isDeltaTemporality(metric)) { + continue; + } + PrometheusType prometheusType = PrometheusType.forMetric(metric); + String metricName = metricName(metric.getName(), prometheusType); + // Skip metrics which do not pass metricNameFilter + if (!metricNameFilter.test(metricName)) { + continue; + } + List metricsWithHeaderName = + metricsByName.computeIfAbsent(metricName, unused -> new ArrayList<>()); + // Skip metrics with the same name but different type + if (metricsWithHeaderName.size() > 0 + && prometheusType != PrometheusType.forMetric(metricsWithHeaderName.get(0))) { + conflictMetricNames.add(metricName); + continue; + } + + metricsWithHeaderName.add(metric); + scopes.add(metric.getInstrumentationScopeInfo()); + } + Optional optResource = metrics.stream().findFirst().map(MetricData::getResource); try (Writer writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) { if (optResource.isPresent()) { writeResource(optResource.get(), writer); } - for (Map.Entry> entry : - metricsByScope.entrySet()) { + for (InstrumentationScopeInfo scope : scopes) { + writeScopeInfo(scope, writer); + } + for (Map.Entry> entry : metricsByName.entrySet()) { write(entry.getValue(), entry.getKey(), writer); } writeEof(writer); } + return conflictMetricNames; } - private void write( - List metrics, InstrumentationScopeInfo instrumentationScopeInfo, Writer writer) - throws IOException { - writeScopeInfo(instrumentationScopeInfo, writer); - // Group metrics with the scope, name, but different types. This is a semantic error which the - // SDK warns about but passes through to exporters to handle. - Map> metricsByName = - metrics.stream() - .collect( - Collectors.groupingBy( - metric -> - headerName( - NameSanitizer.INSTANCE.apply(metric.getName()), - PrometheusType.forMetric(metric)), - LinkedHashMap::new, - Collectors.toList())); - - for (Map.Entry> entry : metricsByName.entrySet()) { - write(entry.getValue(), entry.getKey(), writer); - } - } - - private void write(List metrics, String headerName, Writer writer) + private void write(List metrics, String metricName, Writer writer) throws IOException { // Write header based on first metric - PrometheusType type = PrometheusType.forMetric(metrics.get(0)); + MetricData first = metrics.get(0); + PrometheusType type = PrometheusType.forMetric(first); + String headerName = headerName(NameSanitizer.INSTANCE.apply(first.getName()), type); String description = metrics.get(0).getDescription(); writer.write("# TYPE "); @@ -171,13 +176,11 @@ private void write(List metrics, String headerName, Writer writer) // Then write the metrics. for (MetricData metric : metrics) { - write(metric, writer); + write(metric, metricName, writer); } } - private void write(MetricData metric, Writer writer) throws IOException { - String name = metricName(metric); - + private void write(MetricData metric, String metricName, Writer writer) throws IOException { for (PointData point : getPoints(metric)) { switch (metric.getType()) { case DOUBLE_SUM: @@ -185,7 +188,7 @@ private void write(MetricData metric, Writer writer) throws IOException { writePoint( writer, metric.getInstrumentationScopeInfo(), - name, + metricName, ((DoublePointData) point).getValue(), point.getAttributes(), point.getEpochNanos()); @@ -195,18 +198,18 @@ private void write(MetricData metric, Writer writer) throws IOException { writePoint( writer, metric.getInstrumentationScopeInfo(), - name, + metricName, (double) ((LongPointData) point).getValue(), point.getAttributes(), point.getEpochNanos()); break; case HISTOGRAM: writeHistogram( - writer, metric.getInstrumentationScopeInfo(), name, (HistogramPointData) point); + writer, metric.getInstrumentationScopeInfo(), metricName, (HistogramPointData) point); break; case SUMMARY: writeSummary( - writer, metric.getInstrumentationScopeInfo(), name, (SummaryPointData) point); + writer, metric.getInstrumentationScopeInfo(), metricName, (SummaryPointData) point); break; case EXPONENTIAL_HISTOGRAM: throw new IllegalArgumentException("Can't happen"); @@ -648,9 +651,8 @@ static Collection getPoints(MetricData metricData) { return Collections.emptyList(); } - private static String metricName(MetricData metric) { - PrometheusType type = PrometheusType.forMetric(metric); - String name = NameSanitizer.INSTANCE.apply(metric.getName()); + private static String metricName(String rawMetricName, PrometheusType type) { + String name = NameSanitizer.INSTANCE.apply(rawMetricName); if (type == PrometheusType.COUNTER) { name = name + "_total"; } diff --git a/exporters/prometheus/src/module/java/module-info.java b/exporters/prometheus/src/module/java/module-info.java index 89012f016bd..b675c7bf8ec 100644 --- a/exporters/prometheus/src/module/java/module-info.java +++ b/exporters/prometheus/src/module/java/module-info.java @@ -4,4 +4,5 @@ requires transitive io.opentelemetry.sdk.metrics; requires jdk.httpserver; + requires java.logging; } diff --git a/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java b/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java index dc195825a13..b343d08b2c3 100644 --- a/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java +++ b/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java @@ -17,11 +17,14 @@ import com.linecorp.armeria.common.HttpMethod; import com.linecorp.armeria.common.HttpStatus; import com.linecorp.armeria.common.RequestHeaders; +import io.github.netmikey.logunit.api.LogCapturer; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData; +import io.opentelemetry.sdk.metrics.internal.data.ImmutableGaugeData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData; @@ -31,21 +34,29 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.zip.GZIPInputStream; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; class PrometheusHttpServerTest { - private static final MetricProducer metricProducer = PrometheusHttpServerTest::generateTestData; + private static final AtomicReference> metricData = new AtomicReference<>(); + private static final MetricProducer metricProducer = metricData::get; static PrometheusHttpServer prometheusServer; static WebClient client; + @RegisterExtension + LogCapturer logs = LogCapturer.create().captureForType(PrometheusHttpServer.class); + @BeforeAll - static void setUp() { + static void beforeAll() { // Register the SDK metric producer with the prometheus reader. prometheusServer = PrometheusHttpServer.builder().setHost("localhost").setPort(0).build(); prometheusServer.register(metricProducer); @@ -53,6 +64,11 @@ static void setUp() { client = WebClient.of("http://localhost:" + prometheusServer.getAddress().getPort()); } + @BeforeEach + void beforeEach() { + metricData.set(generateTestData()); + } + @AfterAll static void tearDown() { prometheusServer.shutdown(); @@ -86,12 +102,12 @@ void fetchPrometheus(String endpoint) { + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"grpc\",otel_scope_version=\"version\"} 1\n" - + "# TYPE grpc_name_total counter\n" - + "# HELP grpc_name_total long_description\n" - + "grpc_name_total{otel_scope_name=\"grpc\",otel_scope_version=\"version\",kp=\"vp\"} 5.0 0\n" + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"http\",otel_scope_version=\"version\"} 1\n" + + "# TYPE grpc_name_total counter\n" + + "# HELP grpc_name_total long_description\n" + + "grpc_name_total{otel_scope_name=\"grpc\",otel_scope_version=\"version\",kp=\"vp\"} 5.0 0\n" + "# TYPE http_name_total counter\n" + "# HELP http_name_total double_description\n" + "http_name_total{otel_scope_name=\"http\",otel_scope_version=\"version\",kp=\"vp\"} 3.5 0\n"); @@ -121,12 +137,12 @@ void fetchOpenMetrics(String endpoint) { + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"grpc\",otel_scope_version=\"version\"} 1\n" - + "# TYPE grpc_name counter\n" - + "# HELP grpc_name long_description\n" - + "grpc_name_total{otel_scope_name=\"grpc\",otel_scope_version=\"version\",kp=\"vp\"} 5.0 0.000\n" + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"http\",otel_scope_version=\"version\"} 1\n" + + "# TYPE grpc_name counter\n" + + "# HELP grpc_name long_description\n" + + "grpc_name_total{otel_scope_name=\"grpc\",otel_scope_version=\"version\",kp=\"vp\"} 5.0 0.000\n" + "# TYPE http_name counter\n" + "# HELP http_name double_description\n" + "http_name_total{otel_scope_name=\"http\",otel_scope_version=\"version\",kp=\"vp\"} 3.5 0.000\n" @@ -174,12 +190,12 @@ void fetchPrometheusCompressed() throws IOException { + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"grpc\",otel_scope_version=\"version\"} 1\n" - + "# TYPE grpc_name_total counter\n" - + "# HELP grpc_name_total long_description\n" - + "grpc_name_total{otel_scope_name=\"grpc\",otel_scope_version=\"version\",kp=\"vp\"} 5.0 0\n" + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"http\",otel_scope_version=\"version\"} 1\n" + + "# TYPE grpc_name_total counter\n" + + "# HELP grpc_name_total long_description\n" + + "grpc_name_total{otel_scope_name=\"grpc\",otel_scope_version=\"version\",kp=\"vp\"} 5.0 0\n" + "# TYPE http_name_total counter\n" + "# HELP http_name_total double_description\n" + "http_name_total{otel_scope_name=\"http\",otel_scope_version=\"version\",kp=\"vp\"} 3.5 0\n"); @@ -202,13 +218,84 @@ void fetchHealth() { assertThat(response.contentUtf8()).isEqualTo("Exporter is Healthy."); } + @Test + @SuppressLogger(PrometheusHttpServer.class) + void fetch_DuplicateMetrics() { + Resource resource = Resource.create(Attributes.of(stringKey("kr"), "vr")); + metricData.set( + ImmutableList.of( + ImmutableMetricData.createLongSum( + resource, + InstrumentationScopeInfo.create("scope1"), + "foo", + "description1", + "unit1", + ImmutableSumData.create( + /* isMonotonic= */ true, + AggregationTemporality.CUMULATIVE, + Collections.singletonList( + ImmutableLongPointData.create(123, 456, Attributes.empty(), 1)))), + // A counter with same name as foo but with different scope, description, unit + ImmutableMetricData.createLongSum( + resource, + InstrumentationScopeInfo.create("scope2"), + "foo", + "description2", + "unit2", + ImmutableSumData.create( + /* isMonotonic= */ true, + AggregationTemporality.CUMULATIVE, + Collections.singletonList( + ImmutableLongPointData.create(123, 456, Attributes.empty(), 2)))), + // A gauge whose name conflicts with foo counter's name after the "_total" suffix is + // added + ImmutableMetricData.createLongGauge( + resource, + InstrumentationScopeInfo.create("scope3"), + "foo_total", + "unused", + "unused", + ImmutableGaugeData.create( + Collections.singletonList( + ImmutableLongPointData.create(123, 456, Attributes.empty(), 3)))))); + + AggregatedHttpResponse response = client.get("/").aggregate().join(); + assertThat(response.status()).isEqualTo(HttpStatus.OK); + assertThat(response.headers().get(HttpHeaderNames.CONTENT_TYPE)) + .isEqualTo("text/plain; version=0.0.4; charset=utf-8"); + assertThat(response.contentUtf8()) + .isEqualTo( + "# TYPE target info\n" + + "# HELP target Target metadata\n" + + "target_info{kr=\"vr\"} 1\n" + + "# TYPE otel_scope_info info\n" + + "# HELP otel_scope_info Scope metadata\n" + + "otel_scope_info{otel_scope_name=\"scope1\"} 1\n" + + "# TYPE otel_scope_info info\n" + + "# HELP otel_scope_info Scope metadata\n" + + "otel_scope_info{otel_scope_name=\"scope2\"} 1\n" + + "# TYPE foo_total counter\n" + + "# HELP foo_total description1\n" + + "foo_total{otel_scope_name=\"scope1\"} 1.0 0\n" + + "foo_total{otel_scope_name=\"scope2\"} 2.0 0\n"); + + // Validate conflict warning message + assertThat(logs.getEvents()).hasSize(1); + logs.assertContains( + "Metric conflict(s) detected. Multiple metrics with same name but different type: [foo_total]"); + + // Make another request and confirm warning is only logged once + client.get("/").aggregate().join(); + assertThat(logs.getEvents()).hasSize(1); + } + @Test void stringRepresentation() { assertThat(prometheusServer.toString()) .isEqualTo("PrometheusHttpServer{address=" + prometheusServer.getAddress() + "}"); } - private static ImmutableList generateTestData() { + private static List generateTestData() { return ImmutableList.of( ImmutableMetricData.createLongSum( Resource.create(Attributes.of(stringKey("kr"), "vr")), diff --git a/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/SerializerTest.java b/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/SerializerTest.java index b28e0413635..f6080bd8f50 100644 --- a/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/SerializerTest.java +++ b/exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/SerializerTest.java @@ -47,7 +47,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "monotonic.cumulative.double.sum", "description", "1", ImmutableSumData.create( @@ -66,7 +66,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "non.monotonic.cumulative.double.sum", "description", "1", ImmutableSumData.create( @@ -85,7 +85,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "delta.double.sum", "unused", "1", ImmutableSumData.create( @@ -104,7 +104,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "monotonic.cumulative.long.sum", "unused", "1", ImmutableSumData.create( @@ -123,7 +123,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "non.monotonic.cumulative.long_sum", "unused", "1", ImmutableSumData.create( @@ -142,7 +142,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "delta.long.sum", "unused", "1", ImmutableSumData.create( @@ -162,7 +162,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "double.gauge", "unused", "1", ImmutableGaugeData.create( @@ -176,7 +176,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "long.gauge", "unused", "1", ImmutableGaugeData.create( @@ -190,7 +190,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "summary", "unused", "1", ImmutableSummaryData.create( @@ -211,7 +211,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "delta.histogram", "unused", "1", ImmutableHistogramData.create( @@ -234,7 +234,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "cumulative.histogram.no.attributes", "unused", "1", ImmutableHistogramData.create( @@ -266,7 +266,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "cumulative.histogram.single.attribute", "unused", "1", ImmutableHistogramData.create( @@ -298,7 +298,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "double.gauge.no.attributes", "unused", "1", ImmutableGaugeData.create( @@ -312,7 +312,7 @@ class SerializerTest { .setVersion("version") .setAttributes(Attributes.of(stringKey("ks"), "vs")) .build(), - "instrument.name", + "double.gauge.multiple.attributes", "unused", "1", ImmutableGaugeData.create( @@ -352,28 +352,46 @@ void prometheus004() { + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"full\",otel_scope_version=\"version\",ks=\"vs\"} 1\n" - + "# TYPE instrument_name_total counter\n" - + "# HELP instrument_name_total description\n" - + "instrument_name_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcds\"} 5.0 1633950672000\n" - + "instrument_name_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcls\"} 5.0 1633950672000\n" - + "# TYPE instrument_name gauge\n" - + "# HELP instrument_name description\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcds\"} 5.0 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcls\"} 5.0 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"dg\"} 5.0 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"lg\"} 5.0 1633950672000\n" - + "instrument_name_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 5.0 1633950672000\n" - + "instrument_name_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 7.0 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.9\"} 0.1 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.99\"} 0.3 1633950672000\n" - + "instrument_name_count{otel_scope_name=\"full\",otel_scope_version=\"version\"} 2.0 1633950672000\n" - + "instrument_name_sum{otel_scope_name=\"full\",otel_scope_version=\"version\"} 1.0 1633950672000\n" - + "instrument_name_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",le=\"+Inf\"} 2.0 1633950672000\n" - + "instrument_name_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 2.0 1633950672000\n" - + "instrument_name_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 1.0 1633950672000\n" - + "instrument_name_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\",le=\"+Inf\"} 2.0 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\"} 7.0 1633950672000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",animal=\"bear\",type=\"dgma\"} 8.0 1633950672000\n"); + + "# TYPE monotonic_cumulative_double_sum_total counter\n" + + "# HELP monotonic_cumulative_double_sum_total description\n" + + "monotonic_cumulative_double_sum_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcds\"} 5.0 1633950672000\n" + + "# TYPE non_monotonic_cumulative_double_sum gauge\n" + + "# HELP non_monotonic_cumulative_double_sum description\n" + + "non_monotonic_cumulative_double_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcds\"} 5.0 1633950672000\n" + + "# TYPE monotonic_cumulative_long_sum_total counter\n" + + "# HELP monotonic_cumulative_long_sum_total unused\n" + + "monotonic_cumulative_long_sum_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcls\"} 5.0 1633950672000\n" + + "# TYPE non_monotonic_cumulative_long_sum gauge\n" + + "# HELP non_monotonic_cumulative_long_sum unused\n" + + "non_monotonic_cumulative_long_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcls\"} 5.0 1633950672000\n" + + "# TYPE double_gauge gauge\n" + + "# HELP double_gauge unused\n" + + "double_gauge{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"dg\"} 5.0 1633950672000\n" + + "# TYPE long_gauge gauge\n" + + "# HELP long_gauge unused\n" + + "long_gauge{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"lg\"} 5.0 1633950672000\n" + + "# TYPE summary summary\n" + + "# HELP summary unused\n" + + "summary_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 5.0 1633950672000\n" + + "summary_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 7.0 1633950672000\n" + + "summary{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.9\"} 0.1 1633950672000\n" + + "summary{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.99\"} 0.3 1633950672000\n" + + "# TYPE cumulative_histogram_no_attributes histogram\n" + + "# HELP cumulative_histogram_no_attributes unused\n" + + "cumulative_histogram_no_attributes_count{otel_scope_name=\"full\",otel_scope_version=\"version\"} 2.0 1633950672000\n" + + "cumulative_histogram_no_attributes_sum{otel_scope_name=\"full\",otel_scope_version=\"version\"} 1.0 1633950672000\n" + + "cumulative_histogram_no_attributes_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",le=\"+Inf\"} 2.0 1633950672000\n" + + "# TYPE cumulative_histogram_single_attribute histogram\n" + + "# HELP cumulative_histogram_single_attribute unused\n" + + "cumulative_histogram_single_attribute_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 2.0 1633950672000\n" + + "cumulative_histogram_single_attribute_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 1.0 1633950672000\n" + + "cumulative_histogram_single_attribute_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\",le=\"+Inf\"} 2.0 1633950672000\n" + + "# TYPE double_gauge_no_attributes gauge\n" + + "# HELP double_gauge_no_attributes unused\n" + + "double_gauge_no_attributes{otel_scope_name=\"full\",otel_scope_version=\"version\"} 7.0 1633950672000\n" + + "# TYPE double_gauge_multiple_attributes gauge\n" + + "# HELP double_gauge_multiple_attributes unused\n" + + "double_gauge_multiple_attributes{otel_scope_name=\"full\",otel_scope_version=\"version\",animal=\"bear\",type=\"dgma\"} 8.0 1633950672000\n"); } @Test @@ -401,26 +419,46 @@ void openMetrics() { + "# TYPE otel_scope_info info\n" + "# HELP otel_scope_info Scope metadata\n" + "otel_scope_info{otel_scope_name=\"full\",otel_scope_version=\"version\",ks=\"vs\"} 1\n" - + "# TYPE instrument_name counter\n" - + "# HELP instrument_name description\n" - + "instrument_name_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcds\"} 5.0 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcds\"} 5.0 1633950672.000\n" - + "instrument_name_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcls\"} 5.0 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcls\"} 5.0 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"dg\"} 5.0 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"lg\"} 5.0 1633950672.000\n" - + "instrument_name_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 5.0 1633950672.000\n" - + "instrument_name_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 7.0 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.9\"} 0.1 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.99\"} 0.3 1633950672.000\n" - + "instrument_name_count{otel_scope_name=\"full\",otel_scope_version=\"version\"} 2.0 1633950672.000\n" - + "instrument_name_sum{otel_scope_name=\"full\",otel_scope_version=\"version\"} 1.0 1633950672.000\n" - + "instrument_name_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",le=\"+Inf\"} 2.0 1633950672.000 # {span_id=\"0000000000000002\",trace_id=\"00000000000000000000000000000001\"} 4.0 0.001\n" - + "instrument_name_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 2.0 1633950672.000\n" - + "instrument_name_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 1.0 1633950672.000\n" - + "instrument_name_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\",le=\"+Inf\"} 2.0 1633950672.000 # {span_id=\"0000000000000002\",trace_id=\"00000000000000000000000000000001\"} 4.0 0.001\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\"} 7.0 1633950672.000\n" - + "instrument_name{otel_scope_name=\"full\",otel_scope_version=\"version\",animal=\"bear\",type=\"dgma\"} 8.0 1633950672.000\n" + + "# TYPE monotonic_cumulative_double_sum counter\n" + + "# HELP monotonic_cumulative_double_sum description\n" + + "monotonic_cumulative_double_sum_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcds\"} 5.0 1633950672.000\n" + + "# TYPE non_monotonic_cumulative_double_sum gauge\n" + + "# HELP non_monotonic_cumulative_double_sum description\n" + + "non_monotonic_cumulative_double_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcds\"} 5.0 1633950672.000\n" + + "# TYPE monotonic_cumulative_long_sum counter\n" + + "# HELP monotonic_cumulative_long_sum unused\n" + + "monotonic_cumulative_long_sum_total{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"mcls\"} 5.0 1633950672.000\n" + + "# TYPE non_monotonic_cumulative_long_sum gauge\n" + + "# HELP non_monotonic_cumulative_long_sum unused\n" + + "non_monotonic_cumulative_long_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"nmcls\"} 5.0 1633950672.000\n" + + "# TYPE double_gauge gauge\n" + + "# HELP double_gauge unused\n" + + "double_gauge{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"dg\"} 5.0 1633950672.000\n" + + "# TYPE long_gauge gauge\n" + + "# HELP long_gauge unused\n" + + "long_gauge{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"lg\"} 5.0 1633950672.000\n" + + "# TYPE summary summary\n" + + "# HELP summary unused\n" + + "summary_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 5.0 1633950672.000\n" + + "summary_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\"} 7.0 1633950672.000\n" + + "summary{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.9\"} 0.1 1633950672.000\n" + + "summary{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"s\",quantile=\"0.99\"} 0.3 1633950672.000\n" + + "# TYPE cumulative_histogram_no_attributes histogram\n" + + "# HELP cumulative_histogram_no_attributes unused\n" + + "cumulative_histogram_no_attributes_count{otel_scope_name=\"full\",otel_scope_version=\"version\"} 2.0 1633950672.000\n" + + "cumulative_histogram_no_attributes_sum{otel_scope_name=\"full\",otel_scope_version=\"version\"} 1.0 1633950672.000\n" + + "cumulative_histogram_no_attributes_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",le=\"+Inf\"} 2.0 1633950672.000 # {span_id=\"0000000000000002\",trace_id=\"00000000000000000000000000000001\"} 4.0 0.001\n" + + "# TYPE cumulative_histogram_single_attribute histogram\n" + + "# HELP cumulative_histogram_single_attribute unused\n" + + "cumulative_histogram_single_attribute_count{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 2.0 1633950672.000\n" + + "cumulative_histogram_single_attribute_sum{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\"} 1.0 1633950672.000\n" + + "cumulative_histogram_single_attribute_bucket{otel_scope_name=\"full\",otel_scope_version=\"version\",type=\"hs\",le=\"+Inf\"} 2.0 1633950672.000 # {span_id=\"0000000000000002\",trace_id=\"00000000000000000000000000000001\"} 4.0 0.001\n" + + "# TYPE double_gauge_no_attributes gauge\n" + + "# HELP double_gauge_no_attributes unused\n" + + "double_gauge_no_attributes{otel_scope_name=\"full\",otel_scope_version=\"version\"} 7.0 1633950672.000\n" + + "# TYPE double_gauge_multiple_attributes gauge\n" + + "# HELP double_gauge_multiple_attributes unused\n" + + "double_gauge_multiple_attributes{otel_scope_name=\"full\",otel_scope_version=\"version\",animal=\"bear\",type=\"dgma\"} 8.0 1633950672.000\n" + "# EOF\n"); }