使用Micrometer在SpringBoot中全局应用请求标头中的公制标记



我们有一个应用程序目前正在使用spring云网关,我们需要在全局范围内为每个度量添加一个请求头,这对于框架中的开箱即用度量来说非常容易。当我们想要添加自己的自定义度量时,问题就来了。不会发送任何全局添加的标记。这是我的配置:

@Configuration
public class MetricsConfig {
@Bean
public WebFluxTagsContributor webFluxTagsContributor() {
return (exchange, ex) -> buildRequestTags(exchange);
}
@Bean
public GatewayTagsProvider requestTagsProvider() {
return exchange -> buildRequestTags(exchange);
}
@NotNull
private Tags buildRequestTags(ServerWebExchange serverWebExchange) {
String clientApplication = HeadersUtils.get(serverWebExchange.getRequest().getHeaders(), "X-$%$#%$#");
return Tags.of(Tag.of(MetricTag.APP_FROM.lowered(), clientApplication));
}
}

这就是我的自定义度量添加的地方:

@Component
public class ProviderRoutesHeaderFilter implements WebFilter, Ordered {
private static final Logger LOG = LoggerFactory.getLogger(ProviderRoutesHeaderFilter.class);
public static final String A_HEADER_KEY = "x-*&%^";
private final MeterRegistry meterRegistry;
public ProviderRoutesHeaderFilter(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Override
public int getOrder() {
return -2;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
var request = exchange.getRequest();
if(request.getPath().toString().contains("/someroute/") && !request.getHeaders().containsKey(A_HEADER_KEY)) {
traceUnspecifiedHeader(request);
return chain.filter(exchange.mutate()
.request(request.mutate()
.header(A_HEADER_KEY, NOT_SPECIFIED.name())
.build())
.build());
}
return chain.filter(exchange);
}
private void traceUnspecifiedHeader(ServerHttpRequest request) {
LOG.info(A_HEADER_KEY + " header not specified... applying default header");
Set<Tag> tags = Collections.singleton(Tag.of(MetricTag.PATH.lowered(), request.getPath().value()));
meterRegistry.counter("sp.gateway.a_not_specified", tags).increment();
}
}

有了这个设置,我可以在请求度量中看到标签:

localhost:8080/executor/metrics/spring.cloud.gateway.requests

{
"name": "spring.cloud.gateway.requests",
"description": null,
"baseUnit": "milliseconds",
"measurements": [
{
"statistic": "COUNT",
"value": 1.0
},
{
"statistic": "TOTAL_TIME",
"value": 698.241891
},
{
"statistic": "MAX",
"value": 0.0
}
],
"availableTags": [
{
"tag": "routeUri",
"values": [
"http://www.***.com:80"
]
},
{
"tag": "routeId",
"values": [
"******"
]
},
{
"tag": "httpMethod",
"values": [
"GET"
]
},
{
"tag": "app_from",
"values": [        -----> this is my tag
"andy"
] 
},
{
"tag": "outcome",
"values": [
"CLIENT_ERROR"
]
},
{
"tag": "status",
"values": [
"BAD_REQUEST"
]
},
{
"tag": "httpStatusCode",
"values": [
"400"
]
}
]
}

但不是在我的自定义度量中:localhost:8080/executor/metrics/sp.gateway.a_not_specified

{
"name": "sp.gateway.a_not_specified",
"description": null,
"baseUnit": null,
"measurements": [
{
"statistic": "COUNT",
"value": 2.0
}
],
"availableTags": [
{
"tag": "path",
"values": [
"/pr****/***/**"
]
}
]
}

我是否缺少一些配置来完成此任务?非常感谢。

我认为您可以在处理请求后,通过挂接过滤器来添加框架使用的相同标记,并使用与spring.cloud.gateway.requests使用的相同的标记提供程序,并将自定义标记公开为静态方法。

也许你可以在Mono上使用doFinally方法,比如这样(我还没有测试它是否有效(

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.doFinally(signalType -> {
Set<Tag> tags = Collections.singleton(Tag.of(MetricTag.PATH.lowered(), exchange.getRequest().getPath().value()));
tags.addAll(new GatewayHttpTagsProvider().apply(exchange).stream().toList());
tags.add(buildRequestTags(exchange));
meterRegistry.counter("sp.gateway.a_not_specified", tags).increment();
});
}

最新更新