|
16 | 16 | import com.linecorp.armeria.client.retry.RetryRule;
|
17 | 17 | import com.linecorp.armeria.client.retry.RetryingClient;
|
18 | 18 | import com.linecorp.armeria.common.AggregatedHttpResponse;
|
| 19 | +import com.linecorp.armeria.common.HttpData; |
19 | 20 | import com.linecorp.armeria.common.HttpHeaderNames;
|
20 | 21 | import com.linecorp.armeria.common.HttpMethod;
|
21 | 22 | import com.linecorp.armeria.common.HttpStatus;
|
22 | 23 | import com.linecorp.armeria.common.RequestHeaders;
|
23 | 24 | import io.github.netmikey.logunit.api.LogCapturer;
|
24 | 25 | import io.opentelemetry.api.common.Attributes;
|
| 26 | +import io.opentelemetry.api.metrics.DoubleHistogram; |
25 | 27 | import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
|
26 | 28 | import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
27 | 29 | import io.opentelemetry.sdk.common.export.MemoryMode;
|
| 30 | +import io.opentelemetry.sdk.metrics.Aggregation; |
| 31 | +import io.opentelemetry.sdk.metrics.InstrumentType; |
| 32 | +import io.opentelemetry.sdk.metrics.SdkMeterProvider; |
28 | 33 | import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
|
29 | 34 | import io.opentelemetry.sdk.metrics.data.MetricData;
|
30 | 35 | import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
|
| 36 | +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; |
31 | 37 | import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData;
|
32 | 38 | import io.opentelemetry.sdk.metrics.internal.data.ImmutableGaugeData;
|
33 | 39 | import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData;
|
|
36 | 42 | import io.opentelemetry.sdk.resources.Resource;
|
37 | 43 | import io.prometheus.metrics.exporter.httpserver.HTTPServer;
|
38 | 44 | import io.prometheus.metrics.exporter.httpserver.MetricsHandler;
|
| 45 | +import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_3_25_3.Metrics; |
39 | 46 | import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
| 47 | +import io.prometheus.metrics.shaded.com_google_protobuf_3_25_3.TextFormat; |
40 | 48 | import java.io.ByteArrayInputStream;
|
41 | 49 | import java.io.IOException;
|
42 | 50 | import java.net.ServerSocket;
|
@@ -113,6 +121,9 @@ void invalidConfig() {
|
113 | 121 | assertThatThrownBy(() -> PrometheusHttpServer.builder().setHost(""))
|
114 | 122 | .isInstanceOf(IllegalArgumentException.class)
|
115 | 123 | .hasMessage("host must not be empty");
|
| 124 | + assertThatThrownBy(() -> PrometheusHttpServer.builder().setDefaultAggregationSelector(null)) |
| 125 | + .isInstanceOf(NullPointerException.class) |
| 126 | + .hasMessage("defaultAggregationSelector"); |
116 | 127 | }
|
117 | 128 |
|
118 | 129 | @Test
|
@@ -526,4 +537,75 @@ void toBuilder() {
|
526 | 537 | .hasFieldOrPropertyWithValue("executor", executor)
|
527 | 538 | .hasFieldOrPropertyWithValue("prometheusRegistry", prometheusRegistry);
|
528 | 539 | }
|
| 540 | + |
| 541 | + /** |
| 542 | + * Set the default histogram aggregation to be {@link |
| 543 | + * Aggregation#base2ExponentialBucketHistogram()}. In order to validate that exponential |
| 544 | + * histograms are produced, we request protobuf encoded metrics when scraping since the prometheus |
| 545 | + * text format does not support native histograms. We parse the binary content protobuf payload to |
| 546 | + * the protobuf java bindings, and assert against the string representation. |
| 547 | + */ |
| 548 | + @Test |
| 549 | + void histogramDefaultBase2ExponentialHistogram() throws IOException { |
| 550 | + PrometheusHttpServer prometheusServer = |
| 551 | + PrometheusHttpServer.builder() |
| 552 | + .setHost("localhost") |
| 553 | + .setPort(0) |
| 554 | + .setDefaultAggregationSelector( |
| 555 | + DefaultAggregationSelector.getDefault() |
| 556 | + .with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram())) |
| 557 | + .build(); |
| 558 | + try (SdkMeterProvider meterProvider = |
| 559 | + SdkMeterProvider.builder().registerMetricReader(prometheusServer).build()) { |
| 560 | + DoubleHistogram histogram = meterProvider.get("meter").histogramBuilder("histogram").build(); |
| 561 | + histogram.record(1.0); |
| 562 | + |
| 563 | + WebClient client = |
| 564 | + WebClient.builder("http://localhost:" + prometheusServer.getAddress().getPort()) |
| 565 | + .decorator(RetryingClient.newDecorator(RetryRule.failsafe())) |
| 566 | + // Request protobuf binary encoding, which is required for the prometheus native |
| 567 | + // histogram format |
| 568 | + .addHeader( |
| 569 | + "Accept", |
| 570 | + "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily") |
| 571 | + .build(); |
| 572 | + AggregatedHttpResponse response = client.get("/metrics").aggregate().join(); |
| 573 | + assertThat(response.status()).isEqualTo(HttpStatus.OK); |
| 574 | + assertThat(response.headers().get(HttpHeaderNames.CONTENT_TYPE)) |
| 575 | + .isEqualTo( |
| 576 | + "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"); |
| 577 | + // Parse the data to Metrics.MetricFamily protobuf java binding and assert against the string |
| 578 | + // representation |
| 579 | + try (HttpData data = response.content()) { |
| 580 | + Metrics.MetricFamily metricFamily = |
| 581 | + Metrics.MetricFamily.parseDelimitedFrom(data.toInputStream()); |
| 582 | + String s = TextFormat.printer().printToString(metricFamily); |
| 583 | + assertThat(s) |
| 584 | + .isEqualTo( |
| 585 | + "name: \"histogram\"\n" |
| 586 | + + "help: \"\"\n" |
| 587 | + + "type: HISTOGRAM\n" |
| 588 | + + "metric {\n" |
| 589 | + + " label {\n" |
| 590 | + + " name: \"otel_scope_name\"\n" |
| 591 | + + " value: \"meter\"\n" |
| 592 | + + " }\n" |
| 593 | + + " histogram {\n" |
| 594 | + + " sample_count: 1\n" |
| 595 | + + " sample_sum: 1.0\n" |
| 596 | + + " schema: 8\n" |
| 597 | + + " zero_threshold: 0.0\n" |
| 598 | + + " zero_count: 0\n" |
| 599 | + + " positive_span {\n" |
| 600 | + + " offset: 0\n" |
| 601 | + + " length: 1\n" |
| 602 | + + " }\n" |
| 603 | + + " positive_delta: 1\n" |
| 604 | + + " }\n" |
| 605 | + + "}\n"); |
| 606 | + } |
| 607 | + } finally { |
| 608 | + prometheusServer.shutdown(); |
| 609 | + } |
| 610 | + } |
529 | 611 | }
|
0 commit comments