-
Notifications
You must be signed in to change notification settings - Fork 909
Add config to enable Default Exponential Histogram for Prometheus Exporter #6541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
46fdadc
4fda8cd
a1a8095
7f82907
a468f97
4b9e688
3efa0b7
e0a28d6
9cba997
ade08aa
199482f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,18 +16,24 @@ | |
import com.linecorp.armeria.client.retry.RetryRule; | ||
import com.linecorp.armeria.client.retry.RetryingClient; | ||
import com.linecorp.armeria.common.AggregatedHttpResponse; | ||
import com.linecorp.armeria.common.HttpData; | ||
import com.linecorp.armeria.common.HttpHeaderNames; | ||
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.api.metrics.DoubleHistogram; | ||
import io.opentelemetry.internal.testing.slf4j.SuppressLogger; | ||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo; | ||
import io.opentelemetry.sdk.common.export.MemoryMode; | ||
import io.opentelemetry.sdk.metrics.Aggregation; | ||
import io.opentelemetry.sdk.metrics.InstrumentType; | ||
import io.opentelemetry.sdk.metrics.SdkMeterProvider; | ||
import io.opentelemetry.sdk.metrics.data.AggregationTemporality; | ||
import io.opentelemetry.sdk.metrics.data.MetricData; | ||
import io.opentelemetry.sdk.metrics.export.CollectionRegistration; | ||
import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; | ||
import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData; | ||
import io.opentelemetry.sdk.metrics.internal.data.ImmutableGaugeData; | ||
import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData; | ||
|
@@ -36,7 +42,9 @@ | |
import io.opentelemetry.sdk.resources.Resource; | ||
import io.prometheus.metrics.exporter.httpserver.HTTPServer; | ||
import io.prometheus.metrics.exporter.httpserver.MetricsHandler; | ||
import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_3_25_3.Metrics; | ||
import io.prometheus.metrics.model.registry.PrometheusRegistry; | ||
import io.prometheus.metrics.shaded.com_google_protobuf_3_25_3.TextFormat; | ||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.net.ServerSocket; | ||
|
@@ -113,6 +121,9 @@ void invalidConfig() { | |
assertThatThrownBy(() -> PrometheusHttpServer.builder().setHost("")) | ||
.isInstanceOf(IllegalArgumentException.class) | ||
.hasMessage("host must not be empty"); | ||
assertThatThrownBy(() -> PrometheusHttpServer.builder().setDefaultAggregationSelector(null)) | ||
.isInstanceOf(NullPointerException.class) | ||
.hasMessage("defaultAggregationSelector"); | ||
} | ||
|
||
@Test | ||
|
@@ -526,4 +537,75 @@ void toBuilder() { | |
.hasFieldOrPropertyWithValue("executor", executor) | ||
.hasFieldOrPropertyWithValue("prometheusRegistry", prometheusRegistry); | ||
} | ||
|
||
/** | ||
* Set the default histogram aggregation to be {@link | ||
* Aggregation#base2ExponentialBucketHistogram()}. In order to validate that exponential | ||
* histograms are produced, we request protobuf encoded metrics when scraping since the prometheus | ||
* text format does not support native histograms. We parse the binary content protobuf payload to | ||
* the protobuf java bindings, and assert against the string representation. | ||
*/ | ||
@Test | ||
void histogramDefaultBase2ExponentialHistogram() throws IOException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Abhishekkr3003 I added a test which confirms that base2 exponential histograms are in fact configured by requesting the protobuf binary format from the prometheus server, parsing it to equivalent java bindings, and asserting against its string represetnation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, @jack-berg , for continuing it, I have not been getting time to contribute here lately. |
||
PrometheusHttpServer prometheusServer = | ||
PrometheusHttpServer.builder() | ||
.setHost("localhost") | ||
.setPort(0) | ||
.setDefaultAggregationSelector( | ||
DefaultAggregationSelector.getDefault() | ||
.with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram())) | ||
.build(); | ||
try (SdkMeterProvider meterProvider = | ||
SdkMeterProvider.builder().registerMetricReader(prometheusServer).build()) { | ||
DoubleHistogram histogram = meterProvider.get("meter").histogramBuilder("histogram").build(); | ||
histogram.record(1.0); | ||
|
||
WebClient client = | ||
WebClient.builder("http://localhost:" + prometheusServer.getAddress().getPort()) | ||
.decorator(RetryingClient.newDecorator(RetryRule.failsafe())) | ||
// Request protobuf binary encoding, which is required for the prometheus native | ||
// histogram format | ||
.addHeader( | ||
"Accept", | ||
"application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily") | ||
.build(); | ||
AggregatedHttpResponse response = client.get("/metrics").aggregate().join(); | ||
assertThat(response.status()).isEqualTo(HttpStatus.OK); | ||
assertThat(response.headers().get(HttpHeaderNames.CONTENT_TYPE)) | ||
.isEqualTo( | ||
"application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"); | ||
// Parse the data to Metrics.MetricFamily protobuf java binding and assert against the string | ||
// representation | ||
try (HttpData data = response.content()) { | ||
Metrics.MetricFamily metricFamily = | ||
Metrics.MetricFamily.parseDelimitedFrom(data.toInputStream()); | ||
String s = TextFormat.printer().printToString(metricFamily); | ||
assertThat(s) | ||
.isEqualTo( | ||
"name: \"histogram\"\n" | ||
+ "help: \"\"\n" | ||
+ "type: HISTOGRAM\n" | ||
+ "metric {\n" | ||
+ " label {\n" | ||
+ " name: \"otel_scope_name\"\n" | ||
+ " value: \"meter\"\n" | ||
+ " }\n" | ||
+ " histogram {\n" | ||
+ " sample_count: 1\n" | ||
+ " sample_sum: 1.0\n" | ||
+ " schema: 8\n" | ||
+ " zero_threshold: 0.0\n" | ||
+ " zero_count: 0\n" | ||
+ " positive_span {\n" | ||
+ " offset: 0\n" | ||
+ " length: 1\n" | ||
+ " }\n" | ||
+ " positive_delta: 1\n" | ||
+ " }\n" | ||
+ "}\n"); | ||
} | ||
} finally { | ||
prometheusServer.shutdown(); | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.