Make /metrics the only Prometheus metrics endpoint (#6476)
Signed-off-by: Fabian Stäber <fabian@fstab.de> Co-authored-by: Jack Berg <jberg@newrelic.com>
This commit is contained in:
parent
0f99d70d98
commit
7da7037717
|
@ -10,6 +10,7 @@
|
|||
|
||||
package io.opentelemetry.exporter.prometheus;
|
||||
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.common.export.MemoryMode;
|
||||
import io.opentelemetry.sdk.internal.DaemonThreadFactory;
|
||||
|
@ -18,7 +19,6 @@ import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
|
|||
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
|
||||
import io.opentelemetry.sdk.metrics.export.MetricReader;
|
||||
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
|
||||
import io.prometheus.metrics.exporter.httpserver.MetricsHandler;
|
||||
import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
|
@ -64,7 +64,8 @@ public final class PrometheusHttpServer implements MetricReader {
|
|||
PrometheusRegistry prometheusRegistry,
|
||||
boolean otelScopeEnabled,
|
||||
@Nullable Predicate<String> allowedResourceAttributesFilter,
|
||||
MemoryMode memoryMode) {
|
||||
MemoryMode memoryMode,
|
||||
@Nullable HttpHandler defaultHandler) {
|
||||
this.builder = builder;
|
||||
this.prometheusMetricReader =
|
||||
new PrometheusMetricReader(otelScopeEnabled, allowedResourceAttributesFilter);
|
||||
|
@ -86,7 +87,7 @@ public final class PrometheusHttpServer implements MetricReader {
|
|||
.port(port)
|
||||
.executorService(executor)
|
||||
.registry(prometheusRegistry)
|
||||
.defaultHandler(new MetricsHandler(prometheusRegistry))
|
||||
.defaultHandler(defaultHandler)
|
||||
.buildAndStart();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not create Prometheus HTTP server", e);
|
||||
|
|
|
@ -8,6 +8,7 @@ package io.opentelemetry.exporter.prometheus;
|
|||
import static io.opentelemetry.api.internal.Utils.checkArgument;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import io.opentelemetry.sdk.common.export.MemoryMode;
|
||||
import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
@ -29,6 +30,7 @@ public final class PrometheusHttpServerBuilder {
|
|||
@Nullable private Predicate<String> allowedResourceAttributesFilter;
|
||||
@Nullable private ExecutorService executor;
|
||||
private MemoryMode memoryMode = DEFAULT_MEMORY_MODE;
|
||||
@Nullable private HttpHandler defaultHandler;
|
||||
|
||||
PrometheusHttpServerBuilder() {}
|
||||
|
||||
|
@ -107,6 +109,23 @@ public final class PrometheusHttpServerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default handler for serving the "/", "/**" endpoint.
|
||||
*
|
||||
* <p>This can be used to serve metrics on additional paths besides the default "/metrics". For
|
||||
* example: <code>
|
||||
* PrometheusHttpServer.builder()
|
||||
* .setPrometheusRegistry(prometheusRegistry)
|
||||
* .setDefaultHandler(new MetricsHandler(prometheusRegistry))
|
||||
* .build()
|
||||
* </code>
|
||||
*/
|
||||
public PrometheusHttpServerBuilder setDefaultHandler(HttpHandler defaultHandler) {
|
||||
requireNonNull(defaultHandler, "defaultHandler");
|
||||
this.defaultHandler = defaultHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link PrometheusHttpServer} with the configuration of this builder which can be
|
||||
* registered with a {@link io.opentelemetry.sdk.metrics.SdkMeterProvider}.
|
||||
|
@ -120,6 +139,7 @@ public final class PrometheusHttpServerBuilder {
|
|||
prometheusRegistry,
|
||||
otelScopeEnabled,
|
||||
allowedResourceAttributesFilter,
|
||||
memoryMode);
|
||||
memoryMode,
|
||||
defaultHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData;
|
|||
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
|
||||
import io.prometheus.metrics.exporter.httpserver.MetricsHandler;
|
||||
import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -229,7 +230,7 @@ class PrometheusHttpServerTest {
|
|||
void fetchFiltered() {
|
||||
AggregatedHttpResponse response =
|
||||
client
|
||||
.get("/?name[]=grpc_name_unit_total&name[]=bears_total&name[]=target_info")
|
||||
.get("/metrics?name[]=grpc_name_unit_total&name[]=bears_total&name[]=target_info")
|
||||
.aggregate()
|
||||
.join();
|
||||
assertThat(response.status()).isEqualTo(HttpStatus.OK);
|
||||
|
@ -245,6 +246,47 @@ class PrometheusHttpServerTest {
|
|||
+ "target_info{kr=\"vr\"} 1\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fetchOverrideDefaultHandler() {
|
||||
PrometheusRegistry registry = new PrometheusRegistry();
|
||||
try (PrometheusHttpServer prometheusServer =
|
||||
PrometheusHttpServer.builder()
|
||||
.setHost("localhost")
|
||||
.setPort(0)
|
||||
.setPrometheusRegistry(registry)
|
||||
// Set the default handler to serve metrics on /**
|
||||
.setDefaultHandler(new MetricsHandler(registry))
|
||||
.build()) {
|
||||
prometheusServer.register(
|
||||
new CollectionRegistration() {
|
||||
@Override
|
||||
public Collection<MetricData> collectAllMetrics() {
|
||||
return metricData.get();
|
||||
}
|
||||
});
|
||||
WebClient client =
|
||||
WebClient.builder("http://localhost:" + prometheusServer.getAddress().getPort())
|
||||
.decorator(RetryingClient.newDecorator(RetryRule.failsafe()))
|
||||
.build();
|
||||
|
||||
// Fetch metrics from / instead of /metrics
|
||||
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(
|
||||
"# HELP grpc_name_unit_total long_description\n"
|
||||
+ "# TYPE grpc_name_unit_total counter\n"
|
||||
+ "grpc_name_unit_total{kp=\"vp\",otel_scope_name=\"grpc\",otel_scope_version=\"version\"} 5.0\n"
|
||||
+ "# HELP http_name_unit_total double_description\n"
|
||||
+ "# TYPE http_name_unit_total counter\n"
|
||||
+ "http_name_unit_total{kp=\"vp\",otel_scope_name=\"http\",otel_scope_version=\"version\"} 3.5\n"
|
||||
+ "# TYPE target_info gauge\n"
|
||||
+ "target_info{kr=\"vr\"} 1\n");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@Test
|
||||
void fetchPrometheusCompressed() throws IOException {
|
||||
|
@ -275,7 +317,7 @@ class PrometheusHttpServerTest {
|
|||
@SuppressWarnings("resource")
|
||||
@Test
|
||||
void fetchHead() {
|
||||
AggregatedHttpResponse response = client.head("/").aggregate().join();
|
||||
AggregatedHttpResponse response = client.head("/metrics").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");
|
||||
|
|
Loading…
Reference in New Issue