如何为默认 Spring Boot 2 指标定义附加或自定义标签?
How to define additional or custom tags for default Spring Boot 2 metrics?
最近我用 Micrometer
切换到 Spring Boot 2
。当我获得这些闪亮的新指标时,我与我们的 DevOps 人员进行了交谈,我们开始将它们导出到 Telegraf
。
为了区分不同的应用程序和应用程序节点,我们决定使用标签。这非常适合自定义指标,但现在我开始考虑预定义指标。要为默认指标实现同样的效果,我还需要能够为它们添加额外的标签。
有可能实现吗?我这样做对吗?
编辑: 我尝试了下一个方法:
@Component
public class MyMetricsImpl implements MyMetrics {
@Autowired
protected MyProperties myProperties;
@Autowired
protected MeterRegistry meterRegistry;
@PostConstruct
public void initialize() {
this.meterRegistry.config()
.commonTags(commonTags());
}
@Override
public List<Tag> commonTags() {
List<Tag> tags = new ArrayList<>();
tags.add(Tag.of("application", myProperties.getApplicationName()));
tags.add(Tag.of("node", myProperties.getNodeName()));
return tags;
}
}
问题是我的指标表现正确,甚至 Boot 的一些指标(至少 http.server.requests
)也能看到我的标签。但是 jvm.*
、system.*
、tomcat.*
和许多其他人仍然没有所需的标签。
如果您正在寻找通用标签支持,您可以通过注册一个 MeterFilter
来实现。
有关示例,请参阅 this commit or this branch。
通过the upcoming Spring Boot 2.1.0.M1,您可以使用以下属性:
management.metrics.tags.*= # Common tags that are applied to every meter.
详情见the reference。
更新:
由于问题已更新,我使用这种基于 MeterFilter
的方法检查了更新后的问题,并确认其工作方式如下:
请求:http://localhost:8080/actuator/metrics/jvm.gc.memory.allocated
回复:
{
"name" : "jvm.gc.memory.allocated",
"measurements" : [ {
"statistic" : "COUNT",
"value" : 1.98180864E8
} ],
"availableTags" : [ {
"tag" : "stack",
"values" : [ "prod" ]
}, {
"tag" : "region",
"values" : [ "us-east-1" ]
} ]
}
我没有检查更新问题中提供的方法,但我只会使用经过验证的基于 MeterFilter
的方法,除非有任何理由坚持使用该方法。
第二次更新:
我研究了该方法并能够用 this branch 重现它。
在 @PostConstruct
中应用通用标签为时已晚,因为一些指标已经注册。 http.server.requests
起作用的原因是它将在第一个请求中注册。如果你对它感兴趣,请尝试在 the point of filters' application 上设置断点。
简而言之,试试上面的方法,它类似于即将推出的 Spring 开箱即用支持。
为了回应我原来问题下的评论,这里有一个添加自定义指标的小例子:
package io.github.stepio.examples.metrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyImportantComponent {
protected static final String CONNECTIONS_CURRENT = "connections.created";
protected static final String CONNECTIONS_IDLE = "connections.idle";
protected static final String CONNECTIONS_MAX = "connections.max";
protected static final String PREFIX_REQUESTS_FOR_SERVICE = "requests";
protected static final String SERVICE = "service";
protected AtomicInteger connectionMax = new AtomicInteger();
@Autowired
protected MeterRegistry meterRegistry;
@Override
public List<Tag> tags() {
return new ArrayList<>();
}
@Override
public void trackConnectorsCurrent(AtomicInteger counter) {
this.meterRegistry.gauge(CONNECTIONS_CURRENT, tags(), counter);
}
@Override
public void trackConnectorsIdle(Collection<?> collection) {
this.meterRegistry.gaugeCollectionSize(CONNECTIONS_IDLE, tags(), collection);
}
@Override
public void submitConnectorsMax(final int value) {
this.meterRegistry.gauge(CONNECTIONS_MAX, tags(), this.connectionMax).set(value);
}
@Override
public void incrementRequestsForService(String serviceName) {
this.meterRegistry.counter(PREFIX_REQUESTS_FOR_SERVICE, tags(SERVICE, serviceName)).increment();
}
}
如果您使用 spring-boot-actuator 并且您需要将动态标签添加到默认指标
只需定义一个 WebMvcTagsProvider bean:
WebMvcTagsProvider 的默认实现。
@作者 Jon Schneider
@since 2.0.0
public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider {
@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception) {
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.exception(exception),
WebMvcTags.status(response), WebMvcTags.outcome(response));
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, null));
}
}
对于服务器:
(即 @RestController
)
除了 spring-boot 框架提供的默认标签之外,为 reactive-spring-boot 应用程序添加自定义指标标签。
提供一个或多个 @Beans
实现 WebFluxTagsContributor
或者
要替换默认标签,请提供 @Bean
即 implements WebFluxTagsProvider
.
使用 Spring-WebMVC
作为答案之一。
Ref:
以下实现在 groovy.
import io.micrometer.core.instrument.Tag
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
@Component
class CustomWebClientExchangeTagsProvider implements WebFluxTagsContributor {
final KEY = "key"
/**
* Provides tags to be associated with metrics for the given {@code exchange}.
* @param exchange the exchange
* @param ex the current exception (maybe {@code null})
* @return tags to associate with metrics for the request and response exchange
*/
@Override
Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) {
String apiKey = exchange.request.queryParams[KEY] ?: "default_api_key"
HttpStatus status = exchange.response.statusCode ?: HttpStatus.INTERNAL_SERVER_ERROR
HttpMethod method = exchange.request.method ?: HttpMethod.OPTIONS
String group = (status.value() >= 500 ? "5XX" : (status.value() >= 400) ? "4XX" : (status.value() >= 300) ? "3XX" : "NONE")
Tag statusTag = Tag.of("status", status.value().toString())
Tag methodTag = Tag.of("method", method.toString())
Tag apiKeyTag = Tag.of(KEY, apiKey)
Tag groupTag = Tag.of("group", group)
return Arrays.asList(statusTag, methodTag, apiKeyTag, groupTag)
}
}
指标标签:
为客户端验证:指标 http.client.requests.percentile
或 http.client.requests
。
http://localhost:8010/metrics/http.client.requests
验证服务器:
http://localhost:8010/metrics/http.server.requests
同样,将为 http.server.requests.percentile
个指标添加标签
{
"name": "http.server.requests",
"description": null,
"base_unit": "milliseconds",
"measurements": [
{
"statistic": "COUNT",
"value": 17.0
},
{
"statistic": "TOTAL_TIME",
"value": 8832.186054
},
{
"statistic": "MAX",
"value": 6.514132
}
],
"available_tags": [
{
"tag": "exception",
"values": [
"None",
"ResponseStatusException"
]
},
{
"tag": "method",
"values": [
"GET"
]
},
{
"tag": "application",
"values": [
"myapplication"
]
},
{
"tag": "uri",
"values": [
"/myapplication/v1/abcd",
"/manage/metrics/{requiredMetricName}",
"/manage",
"/manage/metrics",
"/myapplication/v1/windows",
"/**"
]
},
{
"tag": "outcome",
"values": [
"CLIENT_ERROR",
"SERVER_ERROR",
"SUCCESS"
]
},
{
"tag": "key",
"values": [
"default_api_key",
"[abcd]"
]
},
{
"tag": "status",
"values": [
"404",
"200",
"502"
]
},
{
"tag": "group",
"values": [
"4XX",
"NONE",
"5XX"
]
}
]
}
或
如果您正在使用 prometheus
您可以按如下方式验证自定义标签
http://localhost:8010/prometheus
客户:
http_client_requests_seconds_count{application="myapplication",clientName="myhostname.com",method="POST",outcome="CLIENT_ERROR",status="403",uri="/urlIamTryingToHit/v1/list",} 1.0
未为客户端添加,因此没有自定义标签,只有 spring-boot 提供的现有标签。
服务器:
http_server_requests_seconds_sum{application="myapplication",exception="None",group="4XX",key="default_api_key",method="GET",outcome="CLIENT_ERROR",status="404",uri="/manage/metrics/{requiredMetricName}",} 0.004154207
我们可以观察 group="4XX"
、key="default_api_key"
、method="GET"
、status="404"
以及现有的默认标签。
对于客户:
要自定义标签,根据您选择的客户端,您可以提供 @Bean
即 implements RestTemplateExchangeTagsProvider
或 WebClientExchangeTagsProvider
.
RestTemplateExchangeTags
和 WebClientExchangeTags
.
中有方便的静态函数
Ref:
最近我用 Micrometer
切换到 Spring Boot 2
。当我获得这些闪亮的新指标时,我与我们的 DevOps 人员进行了交谈,我们开始将它们导出到 Telegraf
。
为了区分不同的应用程序和应用程序节点,我们决定使用标签。这非常适合自定义指标,但现在我开始考虑预定义指标。要为默认指标实现同样的效果,我还需要能够为它们添加额外的标签。
有可能实现吗?我这样做对吗?
编辑: 我尝试了下一个方法:
@Component
public class MyMetricsImpl implements MyMetrics {
@Autowired
protected MyProperties myProperties;
@Autowired
protected MeterRegistry meterRegistry;
@PostConstruct
public void initialize() {
this.meterRegistry.config()
.commonTags(commonTags());
}
@Override
public List<Tag> commonTags() {
List<Tag> tags = new ArrayList<>();
tags.add(Tag.of("application", myProperties.getApplicationName()));
tags.add(Tag.of("node", myProperties.getNodeName()));
return tags;
}
}
问题是我的指标表现正确,甚至 Boot 的一些指标(至少 http.server.requests
)也能看到我的标签。但是 jvm.*
、system.*
、tomcat.*
和许多其他人仍然没有所需的标签。
如果您正在寻找通用标签支持,您可以通过注册一个 MeterFilter
来实现。
有关示例,请参阅 this commit or this branch。
通过the upcoming Spring Boot 2.1.0.M1,您可以使用以下属性:
management.metrics.tags.*= # Common tags that are applied to every meter.
详情见the reference。
更新:
由于问题已更新,我使用这种基于 MeterFilter
的方法检查了更新后的问题,并确认其工作方式如下:
请求:http://localhost:8080/actuator/metrics/jvm.gc.memory.allocated
回复:
{
"name" : "jvm.gc.memory.allocated",
"measurements" : [ {
"statistic" : "COUNT",
"value" : 1.98180864E8
} ],
"availableTags" : [ {
"tag" : "stack",
"values" : [ "prod" ]
}, {
"tag" : "region",
"values" : [ "us-east-1" ]
} ]
}
我没有检查更新问题中提供的方法,但我只会使用经过验证的基于 MeterFilter
的方法,除非有任何理由坚持使用该方法。
第二次更新:
我研究了该方法并能够用 this branch 重现它。
在 @PostConstruct
中应用通用标签为时已晚,因为一些指标已经注册。 http.server.requests
起作用的原因是它将在第一个请求中注册。如果你对它感兴趣,请尝试在 the point of filters' application 上设置断点。
简而言之,试试上面的方法,它类似于即将推出的 Spring 开箱即用支持。
为了回应我原来问题下的评论,这里有一个添加自定义指标的小例子:
package io.github.stepio.examples.metrics;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyImportantComponent {
protected static final String CONNECTIONS_CURRENT = "connections.created";
protected static final String CONNECTIONS_IDLE = "connections.idle";
protected static final String CONNECTIONS_MAX = "connections.max";
protected static final String PREFIX_REQUESTS_FOR_SERVICE = "requests";
protected static final String SERVICE = "service";
protected AtomicInteger connectionMax = new AtomicInteger();
@Autowired
protected MeterRegistry meterRegistry;
@Override
public List<Tag> tags() {
return new ArrayList<>();
}
@Override
public void trackConnectorsCurrent(AtomicInteger counter) {
this.meterRegistry.gauge(CONNECTIONS_CURRENT, tags(), counter);
}
@Override
public void trackConnectorsIdle(Collection<?> collection) {
this.meterRegistry.gaugeCollectionSize(CONNECTIONS_IDLE, tags(), collection);
}
@Override
public void submitConnectorsMax(final int value) {
this.meterRegistry.gauge(CONNECTIONS_MAX, tags(), this.connectionMax).set(value);
}
@Override
public void incrementRequestsForService(String serviceName) {
this.meterRegistry.counter(PREFIX_REQUESTS_FOR_SERVICE, tags(SERVICE, serviceName)).increment();
}
}
如果您使用 spring-boot-actuator 并且您需要将动态标签添加到默认指标
只需定义一个 WebMvcTagsProvider bean:
WebMvcTagsProvider 的默认实现。
@作者 Jon Schneider
@since 2.0.0
public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider {
@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
Throwable exception) {
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.exception(exception),
WebMvcTags.status(response), WebMvcTags.outcome(response));
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, null));
}
}
对于服务器:
(即 @RestController
)
除了 spring-boot 框架提供的默认标签之外,为 reactive-spring-boot 应用程序添加自定义指标标签。
提供一个或多个 @Beans
实现 WebFluxTagsContributor
或者
要替换默认标签,请提供 @Bean
即 implements WebFluxTagsProvider
.
Spring-WebMVC
作为答案之一。
Ref:
以下实现在 groovy.
import io.micrometer.core.instrument.Tag
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
@Component
class CustomWebClientExchangeTagsProvider implements WebFluxTagsContributor {
final KEY = "key"
/**
* Provides tags to be associated with metrics for the given {@code exchange}.
* @param exchange the exchange
* @param ex the current exception (maybe {@code null})
* @return tags to associate with metrics for the request and response exchange
*/
@Override
Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) {
String apiKey = exchange.request.queryParams[KEY] ?: "default_api_key"
HttpStatus status = exchange.response.statusCode ?: HttpStatus.INTERNAL_SERVER_ERROR
HttpMethod method = exchange.request.method ?: HttpMethod.OPTIONS
String group = (status.value() >= 500 ? "5XX" : (status.value() >= 400) ? "4XX" : (status.value() >= 300) ? "3XX" : "NONE")
Tag statusTag = Tag.of("status", status.value().toString())
Tag methodTag = Tag.of("method", method.toString())
Tag apiKeyTag = Tag.of(KEY, apiKey)
Tag groupTag = Tag.of("group", group)
return Arrays.asList(statusTag, methodTag, apiKeyTag, groupTag)
}
}
指标标签:
为客户端验证:指标 http.client.requests.percentile
或 http.client.requests
。
http://localhost:8010/metrics/http.client.requests
验证服务器:
http://localhost:8010/metrics/http.server.requests
同样,将为 http.server.requests.percentile
个指标添加标签
{
"name": "http.server.requests",
"description": null,
"base_unit": "milliseconds",
"measurements": [
{
"statistic": "COUNT",
"value": 17.0
},
{
"statistic": "TOTAL_TIME",
"value": 8832.186054
},
{
"statistic": "MAX",
"value": 6.514132
}
],
"available_tags": [
{
"tag": "exception",
"values": [
"None",
"ResponseStatusException"
]
},
{
"tag": "method",
"values": [
"GET"
]
},
{
"tag": "application",
"values": [
"myapplication"
]
},
{
"tag": "uri",
"values": [
"/myapplication/v1/abcd",
"/manage/metrics/{requiredMetricName}",
"/manage",
"/manage/metrics",
"/myapplication/v1/windows",
"/**"
]
},
{
"tag": "outcome",
"values": [
"CLIENT_ERROR",
"SERVER_ERROR",
"SUCCESS"
]
},
{
"tag": "key",
"values": [
"default_api_key",
"[abcd]"
]
},
{
"tag": "status",
"values": [
"404",
"200",
"502"
]
},
{
"tag": "group",
"values": [
"4XX",
"NONE",
"5XX"
]
}
]
}
或
如果您正在使用 prometheus
您可以按如下方式验证自定义标签
http://localhost:8010/prometheus
客户:
http_client_requests_seconds_count{application="myapplication",clientName="myhostname.com",method="POST",outcome="CLIENT_ERROR",status="403",uri="/urlIamTryingToHit/v1/list",} 1.0
未为客户端添加,因此没有自定义标签,只有 spring-boot 提供的现有标签。
服务器:
http_server_requests_seconds_sum{application="myapplication",exception="None",group="4XX",key="default_api_key",method="GET",outcome="CLIENT_ERROR",status="404",uri="/manage/metrics/{requiredMetricName}",} 0.004154207
我们可以观察 group="4XX"
、key="default_api_key"
、method="GET"
、status="404"
以及现有的默认标签。
对于客户:
要自定义标签,根据您选择的客户端,您可以提供 @Bean
即 implements RestTemplateExchangeTagsProvider
或 WebClientExchangeTagsProvider
.
RestTemplateExchangeTags
和 WebClientExchangeTags
.
中有方便的静态函数
Ref: