在将spring cloud gateway接入Prometheus之后发现收集到的指标中有很多 uri=“UNKNOWN”,如下:
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds histogram
http_server_requests_seconds{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",quantile="0.95",} 326.417514496
http_server_requests_seconds{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",quantile="0.99",} 326.417514496
http_server_requests_seconds{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",quantile="0.995",} 326.417514496
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="0.01",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="0.02",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="0.05",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="0.1",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="0.3",} 0.0
http_server_requests_seconds_bucket{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="+Inf",} 1.0
http_server_requests_seconds_count{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",} 1.0
http_server_requests_seconds_sum{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",} 328.888017765
# HELP http_server_requests_seconds_max
# TYPE http_server_requests_seconds_max gauge
http_server_requests_seconds_max{exception="None",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",} 328.888017765
这些UNKNOWN的指标都是网关上下转发的请求,因此找一下为UNKNOWN的原因。
首先了解到这些指标是Spring Boot Actuator负责收集的,在源码中找到Tag转换的类:
在spring-boot-actuator-2.1.4.RELEASE.jar中org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTags这个类的public static Tag uri(ServerWebExchange exchange)方法:
/**
* Creates a {@code uri} tag based on the URI of the given {@code exchange}. Uses the
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern if
* available. Falling back to {@code REDIRECTION} for 3xx responses, {@code NOT_FOUND}
* for 404 responses, {@code root} for requests with no path info, and {@code UNKNOWN}
* for all other requests.
* @param exchange the exchange
* @return the uri tag derived from the exchange
*/
public static Tag uri(ServerWebExchange exchange) {
PathPattern pathPattern = exchange
.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
if (pathPattern != null) {
return Tag.of("uri", pathPattern.getPatternString());
}
HttpStatus status = exchange.getResponse().getStatusCode();
if (status != null) {
if (status.is3xxRedirection()) {
return URI_REDIRECTION;
}
if (status == HttpStatus.NOT_FOUND) {
return URI_NOT_FOUND;
}
}
String path = getPathInfo(exchange);
if (path.isEmpty()) {
return URI_ROOT;
}
return URI_UNKNOWN;
}
可以看到String path = getPathInfo(exchange);其实已经拿到了路径,但是却return URI_UNKNOWN;
于是去github上看一下是否有人存在相同的疑问,为什么不返回path?
https://github.com/spring-projects/spring-boot/issues/16208
跟着问题中的回复看到了这个PR(https://github.com/spring-projects/spring-boot/pull/15609),将uri方法修改到了现在的样子,最初实际上返回的就是path:
/**
* Creates a {@code uri} tag based on the URI of the given {@code exchange}. Uses the
* {@link HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} best matching pattern.
* @param exchange the exchange
* @return the uri tag derived from the exchange
*/
public static Tag uri(ServerWebExchange exchange) {
PathPattern pathPattern = exchange
.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
if (pathPattern != null) {
return Tag.of("uri", pathPattern.getPatternString());
}
HttpStatus status = exchange.getResponse().getStatusCode();
if (status != null) {
if (status.is3xxRedirection()) {
return URI_REDIRECTION;
}
if (status == HttpStatus.NOT_FOUND) {
return URI_NOT_FOUND;
}
}
String path = exchange.getRequest().getPath().value();
if (path.isEmpty()) {
return URI_ROOT;
}
return Tag.of("uri", path);
}
这个PR中解释了为什么要返回URI_UNKNOWN,大概的意思就是应该关系本身的指标,同时为了防止指标太多。