Support filtered scrape for Prometheus
See gh-21545
This commit is contained in:
committed by
Stephane Nicoll
parent
c848f80c27
commit
cd1baf18fe
@@ -15,3 +15,14 @@ include::{snippets}/prometheus/curl-request.adoc[]
|
||||
The resulting response is similar to the following:
|
||||
|
||||
include::{snippets}/prometheus/http-response.adoc[]
|
||||
|
||||
|
||||
|
||||
[[prometheus-retrieving-query-parameters]]
|
||||
=== Query Parameters
|
||||
|
||||
The endpoint uses query parameters to limit the samples that it returns.
|
||||
The following table shows the supported query parameters:
|
||||
|
||||
[cols="2,4"]
|
||||
include::{snippets}/prometheus/request-parameters.adoc[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -35,6 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* Tests for generating documentation describing the {@link PrometheusScrapeEndpoint}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Johnny Lim
|
||||
*/
|
||||
class PrometheusScrapeEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@@ -43,6 +46,16 @@ class PrometheusScrapeEndpointDocumentationTests extends MockMvcEndpointDocument
|
||||
this.mockMvc.perform(get("/actuator/prometheus")).andExpect(status().isOk()).andDo(document("prometheus"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void filteredPrometheus() throws Exception {
|
||||
this.mockMvc
|
||||
.perform(get("/actuator/prometheus").param("includedNames",
|
||||
"jvm_memory_used_bytes,jvm_memory_committed_bytes"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("prometheus", requestParameters(parameterWithName("includedNames")
|
||||
.description("Restricts the samples to those that match the names. Optional.").optional())));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseDocumentationConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,19 +19,24 @@ package org.springframework.boot.actuate.metrics.export.prometheus;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
|
||||
import io.prometheus.client.Collector.MetricFamilySamples;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exporter.common.TextFormat;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link Endpoint @Endpoint} that outputs metrics in a format that can be scraped by the
|
||||
* Prometheus server.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Johnny Lim
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@WebEndpoint(id = "prometheus")
|
||||
@@ -44,10 +49,13 @@ public class PrometheusScrapeEndpoint {
|
||||
}
|
||||
|
||||
@ReadOperation(produces = TextFormat.CONTENT_TYPE_004)
|
||||
public String scrape() {
|
||||
public String scrape(@Nullable Set<String> includedNames) {
|
||||
try {
|
||||
Writer writer = new StringWriter();
|
||||
TextFormat.write004(writer, this.collectorRegistry.metricFamilySamples());
|
||||
Enumeration<MetricFamilySamples> samples = (includedNames != null)
|
||||
? this.collectorRegistry.filteredMetricFamilySamples(includedNames)
|
||||
: this.collectorRegistry.metricFamilySamples();
|
||||
TextFormat.write004(writer, samples);
|
||||
return writer.toString();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.actuate.metrics.export.prometheus;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
@@ -28,17 +29,30 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PrometheusScrapeEndpoint}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Johnny Lim
|
||||
*/
|
||||
class PrometheusScrapeEndpointIntegrationTests {
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeHasContentTypeText004(WebTestClient client) {
|
||||
client.get().uri("/actuator/prometheus").exchange().expectStatus().isOk().expectHeader()
|
||||
.contentType(MediaType.parseMediaType(TextFormat.CONTENT_TYPE_004));
|
||||
.contentType(MediaType.parseMediaType(TextFormat.CONTENT_TYPE_004)).expectBody(String.class)
|
||||
.value((body) -> assertThat(body).contains("counter1_total").contains("counter2_total")
|
||||
.contains("counter3_total"));
|
||||
}
|
||||
|
||||
@WebEndpointTest
|
||||
void scrapeWithIncludedNames(WebTestClient client) {
|
||||
client.get().uri("/actuator/prometheus?includedNames=counter1_total,counter2_total").exchange().expectStatus()
|
||||
.isOk().expectHeader().contentType(MediaType.parseMediaType(TextFormat.CONTENT_TYPE_004))
|
||||
.expectBody(String.class).value((body) -> assertThat(body).contains("counter1_total")
|
||||
.contains("counter2_total").doesNotContain("counter3_total"));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -56,7 +70,11 @@ class PrometheusScrapeEndpointIntegrationTests {
|
||||
|
||||
@Bean
|
||||
MeterRegistry registry(CollectorRegistry registry) {
|
||||
return new PrometheusMeterRegistry((k) -> null, registry, Clock.SYSTEM);
|
||||
PrometheusMeterRegistry meterRegistry = new PrometheusMeterRegistry((k) -> null, registry, Clock.SYSTEM);
|
||||
Counter.builder("counter1").register(meterRegistry);
|
||||
Counter.builder("counter2").register(meterRegistry);
|
||||
Counter.builder("counter3").register(meterRegistry);
|
||||
return meterRegistry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user