塞 tag 的代码在org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTags 类中,作用时机是在 MetricsClientHttpRequestInterceptor 拦截器中。当调用执行完成后,会将当次请求 metric 记录下来,在这里就会使用到 RestTemplateExchangeTags 来填充 tags。 下面仅给出 uri 的部分代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/** * Creates a {@code uri} {@code Tag} for the URI of the given {@code request}. * @param request the request * @return the uri tag */ publicstatic Tag uri(HttpRequest request) { return Tag.of("uri", ensureLeadingSlash(stripUri(request.getURI().toString()))); }
/** * Creates a {@code uri} {@code Tag} from the given {@code uriTemplate}. * @param uriTemplate the template * @return the uri tag */ publicstatic Tag uri(String uriTemplate) { Stringuri= (StringUtils.hasText(uriTemplate) ? uriTemplate : "none"); return Tag.of("uri", ensureLeadingSlash(stripUri(uri)));
其余的还有 status 和 clientName 等 tag name。
通过断点,可以看到,这里 request.getURI() 拿到的是带有参数的完整请求链接。
这些 tag 的组装最终在 DefaultRestTemplateExchangeTagsProvider 中完成,并返回一个 列表。
/** * Return the URI of the request (including a query string if any, * but only if it is well-formed for a URI representation). * @return the URI of the request (never {@code null}) */ URI getURI();
/** * Provides {@link Tag Tags} for an exchange performed by a {@link RestTemplate}. * * @author Jon Schneider * @author Andy Wilkinson * @since 2.0.0 */ @FunctionalInterface publicinterfaceRestTemplateExchangeTagsProvider {
/** * Provides the tags to be associated with metrics that are recorded for the given * {@code request} and {@code response} exchange. * @param urlTemplate the source URl template, if available * @param request the request * @param response the response (may be {@code null} if the exchange failed) * @return the tags */ Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response);
}
RestTemplateExchangeTagsProvider 的作用就是为 resttemplate 提供 tag 的,所以这里通过自定义一个 RestTemplateExchangeTagsProvider,来替换DefaultRestTemplateExchangeTagsProvider,以达到我们的目标,大致代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@Override public Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response) { Tag uriTag; // 取 request.getURI().getPath() 作为 uri 的 value if (StringUtils.hasText(request.getURI().getPath())) { uriTag = Tag.of("uri", ensureLeadingSlash(stripUri(request.getURI().getPath()))); } else { uriTag = (StringUtils.hasText(urlTemplate) ? RestTemplateExchangeTags.uri(urlTemplate) : RestTemplateExchangeTags.uri(request)); } return Arrays.asList(RestTemplateExchangeTags.method(request), uriTag, RestTemplateExchangeTags.status(response), RestTemplateExchangeTags.clientName(request)); }
// Even though writes are guarded by meterMapLock, iterators across value space are supported // Hence, we use CHM to support that iteration without ConcurrentModificationException risk privatefinal Map<Id, Meter> meterMap = newConcurrentHashMap<>();
一般情况下不会,这里是因为 spring boot actuator 自己提供了保护机制,对于默认情况,tags 在同一个 metric 下,最多只有 100 个
1 2 3 4 5 6
/** * Maximum number of unique URI tag values allowed. After the max number of * tag values is reached, metrics with additional tag values are denied by * filter. */ privateintmaxUriTags=100;